def test_property_construction_unordered(): """ The purpose of this test is to make sure "chained construction" of properties happens properly. I.e. if we add a property that requires several other properties, these are added as well. """ m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = GasPhaseParameterBlock() m.fs.state = m.fs.properties.build_state_block() nvar = 7 ncon = 1 assert len(list(m.component_data_objects(Var))) == nvar assert len(list(m.component_data_objects(Constraint))) == ncon # Access this property to force the construction of prerequisite # properties. m.fs.state.cp_mass # Make sure dependent properties have been properly added. assert hasattr(m.fs.state, "cp_mol") assert hasattr(m.fs.state, "cp_mol_comp") assert hasattr(m.fs.state, "mw") nvar += len(m.fs.state.cp_mol_comp) nvar += len(m.fs.state.cp_mol) nvar += len(m.fs.state.cp_mass) nvar += len(m.fs.state.mw) ncon += len(m.fs.state.cp_mol_comp) ncon += len(m.fs.state.cp_mol) ncon += len(m.fs.state.cp_mass) ncon += len(m.fs.state.mw) assert len(list(m.component_data_objects(Var))) == nvar assert len(list(m.component_data_objects(Constraint))) == ncon
def _make_model(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.solid_properties = SolidPhaseParameterBlock() m.fs.solid_state = m.fs.solid_properties.build_state_block(default={ "parameters": m.fs.solid_properties, "defined_state": True, }) m.fs.gas_properties = GasPhaseParameterBlock() m.fs.gas_state = m.fs.gas_properties.build_state_block(default={ "parameters": m.fs.gas_properties, "defined_state": True, }) m.fs.reaction_properties = HeteroReactionParameterBlock(default={ "solid_property_package": m.fs.solid_properties, "gas_property_package": m.fs.gas_properties, }) m.fs.reaction_block = m.fs.reaction_properties.reaction_block_class( default={ "parameters": m.fs.reaction_properties, "solid_state_block": m.fs.solid_state, "gas_state_block": m.fs.gas_state, "has_equilibrium": False, }) for var in m.fs.gas_state.define_state_vars().values(): var.fix() for var in m.fs.solid_state.define_state_vars().values(): var.fix() return m
def test_property_construction_ordered(): """ The purpose of this test is to make sure each property can be constructed properly. Further, because we know that these variables form a DAG, we check that the addition of each new property adds one variable and constraint, i.e. that the matching defined in the parameter block is in topological order. """ m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = GasPhaseParameterBlock() m.fs.state = m.fs.properties.build_state_block() nvar = 7 ncon = 1 assert len(list(m.component_data_objects(Var))) == nvar assert len(list(m.component_data_objects(Constraint))) == ncon matching = [ ('mw', 'mw_eqn'), ('dens_mol', 'ideal_gas'), ('dens_mol_comp', 'comp_conc_eqn'), ('dens_mass', 'dens_mass_basis'), ('visc_d', 'visc_d_constraint'), ('diffusion_comp', 'diffusion_comp_constraint'), ('therm_cond', 'therm_cond_constraint'), ('cp_mol_comp', 'cp_shomate_eqn'), ('cp_mol', 'mixture_heat_capacity_eqn'), ('cp_mass', 'cp_mass_basis'), ('enth_mol_comp', 'enthalpy_shomate_eqn'), ('enth_mol', 'mixture_enthalpy_eqn'), ] # Make sure the matching captures all the non-state vars. state_vars = m.fs.state.define_state_vars() n_state_vars = len(state_vars) n_vars = len(m.fs.properties._metadata._properties) assert len(matching) == n_vars - n_state_vars # Make sure we can add constraints one at a time, and only # add one additional variable. This is specific to this # property package. for varname, conname in matching: assert varname not in state_vars var = getattr(m.fs.state, varname) con = getattr(m.fs.state, conname) dim = len(var) nvar += dim ncon += dim assert dim == len(con) assert isinstance(var, Var) assert isinstance(con, Constraint) assert len(list(m.component_data_objects(Var))) == nvar assert len(list(m.component_data_objects(Constraint))) == ncon
def _make_model(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = GasPhaseParameterBlock() m.fs.state = m.fs.properties.build_state_block( default={ # defined_state True because we want to ensure the state # block is square. "defined_state": True, }) for var in m.fs.state.define_state_vars().values(): var.fix() return m
def test_state_vars(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.solid_properties = SolidPhaseParameterBlock() m.fs.solid_state = m.fs.solid_properties.build_state_block( default={ "parameters": m.fs.solid_properties, "defined_state": True, }) m.fs.gas_properties = GasPhaseParameterBlock() m.fs.gas_state = m.fs.gas_properties.build_state_block( default={ "parameters": m.fs.gas_properties, "defined_state": True, }) m.fs.reaction_properties = HeteroReactionParameterBlock( default={ "solid_property_package": m.fs.solid_properties, "gas_property_package": m.fs.gas_properties, }) m.fs.reaction_block = m.fs.reaction_properties.reaction_block_class( default={ "parameters": m.fs.reaction_properties, "solid_state_block": m.fs.solid_state, "gas_state_block": m.fs.gas_state, "has_equilibrium": False, }) for var in m.fs.gas_state.define_state_vars().values(): var.fix() for var in m.fs.solid_state.define_state_vars().values(): var.fix() # Note that these checks are necessary to trigger the construction of # the reaction block variables assert isinstance(m.fs.reaction_block.k_rxn, Var) assert isinstance(m.fs.reaction_block.OC_conv, Var) assert isinstance(m.fs.reaction_block.OC_conv_temp, Var) assert isinstance(m.fs.reaction_block.reaction_rate, Var) assert degrees_of_freedom(m) == 0 rxn_vars = list(m.fs.reaction_block.component_data_objects(Var)) rxn_cons = list(m.fs.reaction_block.component_data_objects(Constraint)) assert len(rxn_vars) == 4 assert len(rxn_cons) == 4
def rxn_prop(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) # Set up thermo props and reaction props m.fs.solid_properties = SolidPhaseParameterBlock() m.fs.solid_state_block = m.fs.solid_properties.build_state_block( default={ "parameters": m.fs.solid_properties, "defined_state": True }) m.fs.gas_properties = GasPhaseParameterBlock() m.fs.gas_state_block = m.fs.gas_properties.build_state_block( default={ "parameters": m.fs.gas_properties, "defined_state": True }) m.fs.reactions = HeteroReactionParameterBlock( default={ "solid_property_package": m.fs.solid_properties, "gas_property_package": m.fs.gas_properties }) m.fs.unit = m.fs.reactions.reaction_block_class( default={ "parameters": m.fs.reactions, "solid_state_block": m.fs.solid_state_block, "gas_state_block": m.fs.gas_state_block, "has_equilibrium": False }) # Fix required variables to make reaction model square # (gas mixture and component densities, # solid particle porosity, density and component fractions) m.fs.gas_state_block.dens_mol.fix(10) m.fs.gas_state_block.dens_mol_comp.fix(10) m.fs.solid_state_block.particle_porosity.fix(0.23) m.fs.solid_state_block.mass_frac_comp["Fe2O3"].fix(0.244) m.fs.solid_state_block.mass_frac_comp["Fe3O4"].fix(0.202) m.fs.solid_state_block.mass_frac_comp["Al2O3"].fix(0.554) m.fs.solid_state_block.dens_mass_skeletal.fix(3125) m.fs.solid_state_block.temperature.fix(1183.15) # K return m
def gas_prop(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) # gas properties and state inlet block m.fs.properties = GasPhaseParameterBlock() m.fs.unit = m.fs.properties.build_state_block(default={ "parameters": m.fs.properties, "defined_state": True }) m.fs.unit.flow_mol.fix(1) m.fs.unit.temperature.fix(450) m.fs.unit.pressure.fix(1.60) m.fs.unit.mole_frac_comp["CO2"].fix(0.0004) m.fs.unit.mole_frac_comp["H2O"].fix(0.0093) m.fs.unit.mole_frac_comp["O2"].fix(0.2095) m.fs.unit.mole_frac_comp["N2"].fix(0.7808) return m
def test_indexed_state_block(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = GasPhaseParameterBlock() m.fs.state = m.fs.properties.build_state_block([1, 2, 3]) assert len(list(m.component_data_objects(Var))) == 21 assert len(list(m.component_data_objects(Constraint))) == 3 for i, state in m.fs.state.items(): assert isinstance(state.flow_mol, Var) assert isinstance(state.temperature, Var) assert isinstance(state.pressure, Var) assert isinstance(state.mole_frac_comp, Var) assert isinstance(state.sum_component_eqn, Constraint) for name, var in state.define_state_vars().items(): # State vars should be included in the metadata with no method assert name in m.fs.properties._metadata._properties assert m.fs.properties._metadata._properties[name]["method"] is None
def main(): # --------------------------------------------------------------------- # Build model # Create a concrete model m = ConcreteModel() # Create a steady-state flowsheet m.fs = FlowsheetBlock(default={"dynamic": False}) # Set up thermo-physical and reaction properties m.fs.gas_properties = GasPhaseParameterBlock() m.fs.solid_properties = SolidPhaseParameterBlock() m.fs.hetero_reactions = HeteroReactionParameterBlock( default={"solid_property_package": m.fs.solid_properties, "gas_property_package": m.fs.gas_properties}) # Build the BFB in the flowsheet m.fs.BFB = BubblingFluidizedBed( default={ "flow_type": "co_current", "finite_elements": 5, "transformation_method": "dae.collocation", "gas_phase_config": {"property_package": m.fs.gas_properties}, "solid_phase_config": {"property_package": m.fs.solid_properties, "reaction_package": m.fs.hetero_reactions }}) # --------------------------------------------------------------------- # Set design and operating variables of the BFB model # Fix design variables m.fs.BFB.number_orifice.fix(2500) # [-] m.fs.BFB.bed_diameter.fix(6.5) # m m.fs.BFB.bed_height.fix(5) # m # Fix inlet port variables for gas and solid m.fs.BFB.gas_inlet.flow_mol[0].fix(1567.79) # mol/s m.fs.BFB.gas_inlet.temperature[0].fix(373) # K m.fs.BFB.gas_inlet.pressure[0].fix(1.86) # bar m.fs.BFB.gas_inlet.mole_frac_comp[0, "O2"].fix(0.2095) m.fs.BFB.gas_inlet.mole_frac_comp[0, "N2"].fix(0.7808) m.fs.BFB.gas_inlet.mole_frac_comp[0, "CO2"].fix(0.0004) m.fs.BFB.gas_inlet.mole_frac_comp[0, "H2O"].fix(0.0093) m.fs.BFB.solid_inlet.flow_mass[0].fix(1230.865) # kg/s # Particle porosity: # The porosity of the OC particle at the inlet is calculated from the # known bulk density of the fresh OC particle (3251.75 kg/m3), and the # skeletal density of the fresh OC particle (calculated from the known # composition of the fresh particle, and the skeletal density of its # components [see the solids property package]) m.fs.BFB.solid_inlet.particle_porosity[0].fix(0.27) m.fs.BFB.solid_inlet.temperature[0].fix(1173.9) # K m.fs.BFB.solid_inlet.mass_frac_comp[0, "Fe2O3"].fix(0.244162011502) m.fs.BFB.solid_inlet.mass_frac_comp[0, "Fe3O4"].fix(0.201998299487) m.fs.BFB.solid_inlet.mass_frac_comp[0, "Al2O3"].fix(0.553839689011) # --------------------------------------------------------------------- # Initialize reactor t_start = time.time() # Run start time # State arguments for initializing property state blocks # Bubble and gas_emulsion temperatures are initialized at solid # temperature because thermal mass of solid >> thermal mass of gas blk = m.fs.BFB gas_phase_state_args = { 'flow_mol': blk.gas_inlet.flow_mol[0].value, 'temperature': blk.solid_inlet.temperature[0].value, 'pressure': blk.gas_inlet.pressure[0].value, 'mole_frac': { 'O2': blk.gas_inlet.mole_frac_comp[0, 'O2'].value, 'N2': blk.gas_inlet.mole_frac_comp[0, 'N2'].value, 'CO2': blk.gas_inlet.mole_frac_comp[0, 'CO2'].value, 'H2O': blk.gas_inlet.mole_frac_comp[0, 'H2O'].value}} solid_phase_state_args = { 'flow_mass': blk.solid_inlet.flow_mass[0].value, 'particle_porosity': blk.solid_inlet.particle_porosity[0].value, 'temperature': blk.solid_inlet.temperature[0].value, 'mass_frac': { 'Fe2O3': blk.solid_inlet.mass_frac_comp[0, 'Fe2O3'].value, 'Fe3O4': blk.solid_inlet.mass_frac_comp[0, 'Fe3O4'].value, 'Al2O3': blk.solid_inlet.mass_frac_comp[0, 'Al2O3'].value}} m.fs.BFB.initialize(outlvl=idaeslog.INFO, gas_phase_state_args=gas_phase_state_args, solid_phase_state_args=solid_phase_state_args) t_initialize = time.time() # Initialization time # --------------------------------------------------------------------- # Final solve # Create a solver solver = SolverFactory('ipopt') solver.solve(m.fs.BFB, tee=True) t_simulation = time.time() # Simulation time print("\n") print("----------------------------------------------------------") print('Total initialization time: ', value(t_initialize - t_start), " s") print("----------------------------------------------------------") print("\n") print("----------------------------------------------------------") print('Total simulation time: ', value(t_simulation - t_start), " s") print("----------------------------------------------------------") return m