예제 #1
0
def test_init():
    m, solver = blr.main()
    
    # initialize each unit at the time
    blr.initialize(m)
    blr.unfix_inlets(m)
    # check that the model solved properly and has 0 degrees of freedom
    assert(degrees_of_freedom(m)==0)
예제 #2
0
def test_boiler():
    m, solver = blr.main()
        
    # initialize each unit at the time
    blr.initialize(m)
   # unfix inlets to build arcs at the flowsheet level
    blr.unfix_inlets(m)
    m.fs.ATMP1.outlet.enth_mol[0].fix(62710.01)
    m.fs.ATMP1.SprayWater.flow_mol[0].unfix()
    result = solver.solve(m, tee=False)
    assert result.solver.termination_condition == \
            pyo.TerminationCondition.optimal
    assert result.solver.status == pyo.SolverStatus.ok
        
    assert pyo.value(m.fs.ECON.side_1.properties_out[0].temperature) == \
        pytest.approx(521.009,1)
예제 #3
0
def main():
    # import steam cycle and build concrete model
    m, solver = import_steam_cycle()
    print(degrees_of_freedom(m))
    # at this point we have a flowsheet with "steam cycle" that solves
    # correctly, with 0 degrees of freedom.

    # next step is to import and build the boiler heat exchanger network
    # importing the boiler heat exchanger network
    # from (boiler_subflowsheet_build.py)
    # this step appends all the boiler unit models into our model ("m")
    # model "m" has been created a few lines above
    import idaes.power_generation.flowsheets.\
        supercritical_power_plant.boiler_subflowsheet_build as blr
    # import the models (ECON, WW, PrSH, PlSH, FSH, Spliter, Mixer, Reheater)
    # see boiler_subflowhseet_build.py for a beter description
    blr.build_boiler(m.fs)
    # initialize boiler network models (one by one)
    blr.initialize(m)
    # at this point we have both flowsheets (steam cycle + boiler network)
    # in the same model/concrete object ("m"), however they are disconnected.
    # Here we want to solve them at the same time
    # this is a square problem (i.e. degrees of freedom = 0)
    print('solving square problem disconnected')
    results = solver.solve(m, tee=True)

    # at this point we want to connect the units in both flowsheets
    # Economizer inlet = Feed water heater 8 outlet (water)
    # HP inlet = Attemperator outlet (steam)
    # Reheater inlet (steam) = HP split 7 outlet (last stage of HP turbine)
    # IP inlet = Reheater outlet steam7
    blr.unfix_inlets(m)
    print('unfix inlet conditions, degreeso of freedom = ' +
          str(degrees_of_freedom(m)))
    # user can save the initialization to a json file (uncomment next line)
    #    MS.to_json(m, fname = 'SCPC_full.json')
    #   later user can use the json file to initialize the model
    #   if this is the case comment out previous MS.to_json and uncomment next line
    #    MS.from_json(m, fname = 'SCPC_full.json')

    # deactivate constraints linking the FWH8 to HP turbine
    m.fs.boiler_pressure_drop.deactivate()
    m.fs.close_flow.deactivate()
    m.fs.turb.constraint_reheat_flow.deactivate()
    m.fs.turb.constraint_reheat_press.deactivate()
    m.fs.turb.constraint_reheat_temp.deactivate()
    m.fs.turb.inlet_split.inlet.enth_mol.unfix()
    m.fs.turb.inlet_split.inlet.pressure.unfix()
    # user can fix the boiler feed water pump pressure (uncomenting next line)
    #    m.fs.bfp.outlet.pressure[:].fix(26922222.222))

    m.fs.FHWtoECON = Arc(source=m.fs.fwh8.desuperheat.outlet_2,
                         destination=m.fs.ECON.side_1_inlet)

    m.fs.Att2HP = Arc(source=m.fs.ATMP1.outlet,
                      destination=m.fs.turb.inlet_split.inlet)

    m.fs.HPout2RH = Arc(source=m.fs.turb.hp_split[7].outlet_1,
                        destination=m.fs.RH.side_1_inlet)

    m.fs.RHtoIP = Arc(source=m.fs.RH.side_1_outlet,
                      destination=m.fs.turb.ip_stages[1].inlet)

    pyo.TransformationFactory("network.expand_arcs").apply_to(m)

    # unfix boiler connections
    m.fs.ECON.side_1_inlet.flow_mol.unfix()
    m.fs.ECON.side_1_inlet.enth_mol[0].unfix()
    m.fs.ECON.side_1_inlet.pressure[0].unfix()
    m.fs.RH.side_1_inlet.flow_mol.unfix()
    m.fs.RH.side_1_inlet.enth_mol[0].unfix()
    m.fs.RH.side_1_inlet.pressure[0].unfix()
    m.fs.hotwell.makeup.flow_mol[:].setlb(-1.0)

    # if user has trouble with infeasible solutions, an easy test
    # is to deactivate the link to HP turbine
    # (m.fs.Att2HP_expanded "enth_mol and pressure" equalities)
    # and fix inlet pressure and enth_mol to turbine
    # (m.fs.turb.inlet_split.inlet)
    # (then double check the values from m.fs.ATMP1.outlet)
    #  m.fs.Att2HP_expanded.enth_mol_equality.deactivate()
    #  m.fs.Att2HP_expanded.pressure_equality.deactivate()
    m.fs.turb.inlet_split.inlet.pressure.fix(2.423e7)
    #    m.fs.turb.inlet_split.inlet.enth_mol.fix(62710.01)

    # finally, since we want to maintain High Pressure (HP) inlet temperature
    # constant (~866 K), we need to fix Attemperator enthalpy outlet
    # and unfix heat duty to Platen superheater, note that fixing enthalpy
    # to control temperature is only valid because pressure is also fixed
    m.fs.ATMP1.outlet.enth_mol[0].fix(62710.01)
    m.fs.PlSH.heat_duty[:].unfix()  # fix(5.5e7)
    #    m.fs.ATMP1.SprayWater.flow_mol[0].unfix()
    print('connecting flowsheets, degrees of freedom = ' +
          str(degrees_of_freedom(m)))
    print('solving full plant model')
    solver.options = {
        "tol": 1e-6,
        "linear_solver": "ma27",
        "max_iter": 40,
    }
    # square problems tend to work better without bounds
    strip_bounds = pyo.TransformationFactory('contrib.strip_var_bounds')
    strip_bounds.apply_to(m, reversible=True)
    # this is the final solve with both flowsheets connected
    results = solver.solve(m, tee=True)
    return m, results
예제 #4
0
def test_init(boiler):
    # initialize each unit at the time
    blr.initialize(boiler)
    blr.unfix_inlets(boiler)
    # check that the model solved properly and has 0 degrees of freedom
    assert (degrees_of_freedom(boiler) == 0)
예제 #5
0
def boiler_flowsheet():
    """
    Make the flowsheet object, fix some variables, and solve the problem
    """
    import idaes.power_generation.flowsheets.\
        supercritical_power_plant.boiler_subflowsheet_build as blr
    # First, we import the boler model from boiler_subflowsheet_build
    m, solver = blr.main()
    # initialize boiler flowsheet
    blr.initialize(m)
    # unfix inlet values to each unit and build the flowsheet connectivity
    blr.unfix_inlets(m)
    results = solver.solve(m, tee=True)
    print(results)

    # adding boiler block
    # The model solved in line 116 considers heat to platen superheater,
    # heat to water wall, and flue gas inlet to finishing superheater as fixed
    # variables. This code uses simplified surrogate models for these inputs.
    # Therefore, in the new model, these variables will change with plant load,
    # More details regarding this methodology can be found in Zamarripa et al.,
    # FOCAPD 2 page paper included in this directory as FOCAPD_paper.pdf
    m.fs.SR = pyo.Var(initialize=1.15, doc='stoichiometric ratio')
    m.fs.SR.setlb(1.0)
    m.fs.SR.setub(1.25)
    m.fs.SR.fix(1.15)
    m.fs.coal_flow = pyo.Var(initialize=54.01, doc='coal flowrate kg.s')
    m.fs.FGET = pyo.Var(initialize=1300.00, doc='flue gas exit temperature K')
    m.fs.FG_flow = pyo.Var(m.fs.prop_fluegas.component_list,
                           initialize=2000,
                           domain=pyo.Reals,
                           doc='component molar flow rate')
    init_fg = {
        "H2O": (8.69 / 100),
        "CO2": (14.49 / 100),
        "N2": (0.6999),
        "O2": (2.47 / 100),
        "NO": 0.0006,
        "SO2": (0.002)
    }
    m.fs.fg_frac = pyo.Var(m.fs.prop_fluegas.component_list,
                           initialize=init_fg,
                           doc='flue gas molar fraction')

    # surrogate models valid for coal flowrate (30 to 70 kg/s) and SR (1-2.5)
    def fg_mol_frac_rule(b, i):
        if i == 'CO2':
            return m.fs.fg_frac[i] == 0.23235491508307534735955\
                * m.fs.SR**-0.5
        elif i == 'H2O':
            return m.fs.fg_frac[i] == 0.45009703293861530459807E-001 \
                * m.fs.SR
        elif i == 'N2':
            return m.fs.fg_frac[i] == 1 - (
                m.fs.fg_frac['CO2'] + m.fs.fg_frac['H2O'] +
                m.fs.fg_frac['NO'] + m.fs.fg_frac['O2'] + m.fs.fg_frac['SO2'])
        elif i == 'NO':
            return m.fs.fg_frac[i] == 0.38148020722713599076938E-005 \
                * m.fs.coal_flow
        elif i == 'O2':
            return m.fs.fg_frac[i] == 0.60149266916011525155317E-003 \
                * m.fs.coal_flow
        elif i == 'SO2':
            return m.fs.fg_frac[i] == 0.21991717807021016347323E-004 \
                * m.fs.coal_flow

    m.fs.fg_mol_cn = pyo.Constraint(m.fs.prop_fluegas.component_list,
                                    rule=fg_mol_frac_rule)

    def fg_flow_rule(b, i):
        mass_flow = 0.87757407893140026988732 * m.fs.coal_flow \
            - 0.68240933480416252066014E-001 * m.fs.SR + 8.6386912890637752582\
            * m.fs.coal_flow*m.fs.SR - 0.11737247790640543564002E-003 \
            * (m.fs.coal_flow/m.fs.SR)**2  # ~ 28.3876e3 kg/s

        # flow mol component in mol/s = kg/s/kg/mol
        return m.fs.FSH.side_2.properties_in[0].flow_mol_comp[i] == \
            (mass_flow / sum(m.fs.fg_frac[c]*m.fs.prop_fluegas.mw_comp[c]
                             for c in m.fs.prop_fluegas.component_list))\
            * m.fs.fg_frac[i]

    m.fs.fg_flow_cn = pyo.Constraint(m.fs.prop_fluegas.component_list,
                                     rule=fg_flow_rule)

    def fg_temp_rule(b):
        return m.fs.FSH.side_2.properties_in[0].temperature == \
            59836.381548557488713413 * m.fs.coal_flow**-0.5 \
            + 791.74814907302368283126 * m.fs.coal_flow**0.5 \
            + 0.60200443235342349090899 * m.fs.coal_flow**1.5 \
            + 285.74858049626226375040 * m.fs.SR**3 - 29865.27413896147845662\
            * (m.fs.coal_flow*m.fs.SR)**-.5 - 518.58090213915738786454 \
            * (m.fs.coal_flow*m.fs.SR)**0.5 - 0.86351166781748790735040E-002 \
            * (m.fs.coal_flow*m.fs.SR)**2 - 30141.308801694875000976 \
            * (m.fs.SR/m.fs.coal_flow)**0.5 - 18.109911868067683826666 \
            * m.fs.coal_flow/m.fs.SR + 1017.0807559525446777116 \
            * m.fs.SR/m.fs.coal_flow

    m.fs.fg_temp_cn = pyo.Constraint(rule=fg_temp_rule)

    def heat_2_PLSH_rule(b):
        return m.fs.PlSH.heat_duty[0] == - 42149808.046329699456692 \
            * pyo.log(m.fs.coal_flow) + 13125913.817196270450950 \
            * pyo.exp(m.fs.SR) - 82168941.403612509369850 \
            * m.fs.coal_flow**-.5 - 20751.165176131220505340 \
            * (m.fs.coal_flow*m.fs.SR)**1.5 + 35303843.583323523402214 \
            * (m.fs.coal_flow/m.fs.SR)**0.5

    m.fs.heat_2_PLSH_cn = pyo.Constraint(rule=heat_2_PLSH_rule)

    def heat_2_ww_rule(b):
        heat_total = 15383517.068522246554494 * m.fs.coal_flow \
            - 145195958.70188459753990 * m.fs.SR**0.5 + 91548063.4268338829278\
            * (m.fs.coal_flow*m.fs.SR)**0.5 - 11732787.822234204038978 \
            * m.fs.coal_flow*m.fs.SR - 19639.552666366322227987 \
            * (m.fs.coal_flow/m.fs.SR)**2
        return m.fs.Water_wall.heat_duty[0] == heat_total \
            - m.fs.PlSH.heat_duty[0]

    m.fs.heat_2_ww_cn = pyo.Constraint(rule=heat_2_ww_rule)

    # unfix variables to build flowsheet connections
    m.fs.PlSH.heat_duty.unfix()
    m.fs.Water_wall.heat_duty.unfix()
    m.fs.FSH.side_2.properties_in[:].flow_mol_comp.unfix()
    m.fs.FSH.side_2.properties_in[:].temperature.unfix()
    m.fs.coal_flow.fix(50.15)
    print('degrees of freedom = ' + str(degrees_of_freedom(m)))
    # initialize surrogate models (better initial point before solve)
    calculate_variable_from_constraint(m.fs.PlSH.heat_duty[0],
                                       m.fs.heat_2_PLSH_cn)
    calculate_variable_from_constraint(m.fs.Water_wall.heat_duty[0],
                                       m.fs.heat_2_ww_cn)
    # set scaling parameters
    iscale.calculate_scaling_factors(m)
    # final solve
    results = solver.solve(m, tee=False)
    return m
예제 #6
0
    # import steam cycle and build concrete model
    m, solver = import_steam_cycle()
    print(degrees_of_freedom(m))
    #at this point we have a flowsheet with "steam cycle" that solves
    # correctly, with 0 degrees of freedom.

    # next step is to import and build the boiler heat exchanger network
    # importing the boiler heat exchanger network from (boiler_subflowsheet_build.py)
    # will basically append all the unit models into our model ("m")
    # model "m" has been created a few lines above
    import idaes.power_generation.flowsheets.supercritical_power_plant.boiler_subflowsheet_build as blr
    # import the models (ECON, WW, PrSH, PlSH, FSH, Spliter, Mixer, Reheater)
    # see boiler_subflowhseet_build.py for a beter description
    blr.build_boiler(m.fs)
    #initialize boiler network models (one by one)
    blr.initialize(m)
    # at this point we have both flowsheets (steam cycle + boiler network)
    # in the same model/concrete object ("m")
    # however they are disconnected. Here we want to solve them at the same time
    # this is a square problem (i.e. degrees of freedom = 0)
    print('solving square problem disconnected')
    results = solver.solve(m, tee=True)

    # at this point we want to connect the units in both flowsheets
    # Economizer inlet = Feed water heater 8 outlet (water)
    # HP inlet = Attemperator outlet (steam)
    # Reheater inlet (steam) = HP split 7 outlet (last stage of HP turbine)
    # IP inlet = Reheater outlet steam7
    blr.unfix_inlets(m)
    print('unfix inlet conditions, degreeso of freedom = ' +
          str(degrees_of_freedom(m)))
예제 #7
0
def test_power_plan():
    # import steam cycle and build concrete model
    m, solver = steam_cycle.main()
    print(degrees_of_freedom(m))
    #at this point we have a flowsheet with "steam cycle" that solves 
    # correctly, with 0 degrees of freedom.
    
    # next step is to import and build the boiler heat exchanger network
    # importing the boiler heat exchanger network from (boiler_subflowsheet_build.py)
    # will basically append all the unit models into our model ("m") 
    # model "m" has been created a few lines above
    
        # import the models (ECON, WW, PrSH, PlSH, FSH, Spliter, Mixer, Reheater)
        # see boiler_subflowhseet_build.py for a beter description
    blr.build_boiler(m.fs)
    #initialize boiler network models (one by one)
    blr.initialize(m)
    # at this point we have both flowsheets (steam cycle + boiler network)
    # in the same model/concrete object ("m")
    # however they are disconnected. Here we want to solve them at the same time
    # this is a square problem (i.e. degrees of freedom = 0)
#    print('solving square problem disconnected')
    results = solver.solve(m, tee=True)
    
    # at this point we want to connect the units in both flowsheets
    # Economizer inlet = Feed water heater 8 outlet (water)
    # HP inlet = Attemperator outlet (steam)
    # Reheater inlet (steam) = HP split 7 outlet (last stage of HP turbine)
    # IP inlet = Reheater outlet steam7
    blr.unfix_inlets(m)
    
    # deactivate constraints linking the FWH8 to HP turbine
    m.fs.boiler_pressure_drop.deactivate()
    m.fs.close_flow.deactivate()
    m.fs.turb.constraint_reheat_flow.deactivate()
    m.fs.turb.constraint_reheat_press.deactivate()
    m.fs.turb.constraint_reheat_temp.deactivate()
    m.fs.turb.inlet_split.inlet.enth_mol.unfix()
    m.fs.turb.inlet_split.inlet.pressure.unfix()
    
    m.fs.FHWtoECON = Arc(source = m.fs.fwh8.desuperheat.outlet_2,
                      destination = m.fs.ECON.side_1_inlet)
    
    m.fs.Att2HP = Arc(source = m.fs.ATMP1.outlet,
                   destination = m.fs.turb.inlet_split.inlet)
    
    m.fs.HPout2RH = Arc(source = m.fs.turb.hp_split[7].outlet_1,
                     destination = m.fs.RH.side_1_inlet)
    
    m.fs.RHtoIP = Arc(source = m.fs.RH.side_1_outlet,
                   destination =m.fs.turb.ip_stages[1].inlet)
    
    pyo.TransformationFactory("network.expand_arcs").apply_to(m)
    
    #unfix boiler connections
    m.fs.ECON.side_1_inlet.flow_mol.unfix()
    m.fs.ECON.side_1_inlet.enth_mol[0].unfix()
    m.fs.ECON.side_1_inlet.pressure[0].unfix()
    m.fs.RH.side_1_inlet.flow_mol.unfix()
    m.fs.RH.side_1_inlet.enth_mol[0].unfix()
    m.fs.RH.side_1_inlet.pressure[0].unfix()
    m.fs.hotwell.makeup.flow_mol[:].setlb(-1.0)
    
#    if user has trouble with infeasible solutions, an easy test 
#    is to deactivate the link to HP turbine (m.fs.Att2HP_expanded "enth_mol and pressure" equalities) 
#    and fix inlet pressure and enth_mol to turbine (m.fs.turb.inlet_split.inlet)
    m.fs.turb.inlet_split.inlet.pressure.fix(2.423e7)
#   finally, since we want to maintain High Pressure (HP) inlet temperature constant (~866 K)
#   we need to fix Attemperator enthalpy outlet and unfix heat duty to Platen superheater
#   note fixing enthalpy to control temperature is only valid because pressure is also fixed
    m.fs.ATMP1.outlet.enth_mol[0].fix(62710.01)
    m.fs.PlSH.heat_duty[:].unfix()

    
#    print(degrees_of_freedom(m))
    solver.options = {
        "tol": 1e-6,
        "linear_solver": "ma27",
        "max_iter": 40,
    }
    #square problems tend to work better without bounds
    strip_bounds = pyo.TransformationFactory('contrib.strip_var_bounds')
    strip_bounds.apply_to(m, reversible=True)
    # this is the final solve with both flowsheets connected
    results = solver.solve(m, tee=True)
    strip_bounds.revert(m)