Example #1
0
    def initialize(blk, state_args=None, outlvl=idaeslog.NOTSET,
                   solver=None, optarg=None):
        '''
        Downcomer initialization routine.

        Keyword Arguments:
            state_args : a dict of arguments to be passed to the property
                           package(s) for the control_volume of the model to
                           provide an initial state for initialization
                           (see documentation of the specific property package)
                           (default = None).
            outlvl : sets output level of initialisation routine
            optarg : solver options dictionary object (default=None, use
                     default solver options)
            solver : str indicating which solver to use during
                     initialization (default = None, use default solver)

        Returns:
            None
        '''
        init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="unit")
        solve_log = idaeslog.getSolveLogger(blk.name, outlvl, tag="unit")

        # Create solver
        opt = get_solver(solver, optarg)

        init_log.info_low("Starting initialization...")

        flags = blk.control_volume.initialize(
            outlvl=outlvl+1,
            optarg=optarg,
            solver=solver,
            state_args=state_args,
        )
        init_log.info_high("Initialization Step 1 Complete.")
        # make sure 0 DoF
        if degrees_of_freedom(blk) != 0:
            raise ConfigurationError(
                "Incorrect degrees of freedom when initializing {}: dof = {}".format(
                    blk.name, degrees_of_freedom(blk)))
        # Fix outlet pressure
        for t in blk.flowsheet().config.time:
            blk.control_volume.properties_out[t].pressure.fix(
                value(blk.control_volume.properties_in[t].pressure)
            )
        blk.pressure_change_total_eqn.deactivate()

        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            res = opt.solve(blk, tee=slc.tee)
        init_log.info_high(
                "Initialization Step 2 {}.".format(idaeslog.condition(res))
            )

        # Unfix outlet enthalpy and pressure
        for t in blk.flowsheet().config.time:
            blk.control_volume.properties_out[t].pressure.unfix()
        blk.pressure_change_total_eqn.activate()

        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            res = opt.solve(blk, tee=slc.tee)
        init_log.info_high(
                "Initialization Step 3 {}.".format(idaeslog.condition(res))
            )
        blk.control_volume.release_state(flags, outlvl+1)
        init_log.info("Initialization Complete.")
Example #2
0
def initialize_by_element_in_range(model,
                                   time,
                                   t_start,
                                   t_end,
                                   time_linking_vars=[],
                                   dae_vars=[],
                                   max_linking_range=0,
                                   **kwargs):
    """Function for solving a square model, time element-by-time element,
    between specified start and end times.

    Args:
        model : Flowsheet model to solve
        t_start : Beginning of timespan over which to solve
        t_end : End of timespan over which to solve

    Kwargs:
        solver : Solver option used to solve portions of the square model
        outlvl : idaes.logger output level
    """
    solver = kwargs.pop('solver', SolverFactory('ipopt'))
    outlvl = kwargs.pop('outlvl', idaeslog.NOTSET)
    init_log = idaeslog.getInitLogger('nmpc', outlvl)
    solver_log = idaeslog.getSolveLogger('nmpc', outlvl)
    solve_initial_conditions = kwargs.pop('solve_initial_conditions', False)

    #TODO: Move to docstring
    # Variables that will be fixed for time points outside the finite element
    # when constraints for a finite element are activated.
    # For a "normal" process, these should just be differential variables
    # (and maybe derivative variables). For a process with a (PID) controller,
    # these should also include variables used by the controller.
    # If these variables are not specified,

    # Timespan over which these variables will be fixed, counting backwards
    # from the first time point in the finite element (which will always be
    # fixed)
    # Should I specify max_linking_range as an integer number of finite
    # elements, an integer number of time points, or a float in actual time
    # units? Go with latter for now.

    assert t_start in time.get_finite_elements()
    assert t_end in time.get_finite_elements()
    #assert degrees_of_freedom(model) == 0
    # No need to check dof here as we will check right before each solve

    #dae_vars = kwargs.pop('dae_vars', [])
    if not dae_vars:
        scalar_vars, dae_vars = flatten_dae_components(model, time, ctype=Var)
        for var in scalar_vars:
            var.fix()
        deactivate_constraints_unindexed_by(model, time)

    ncp = time.get_discretization_info()['ncp']

    fe_in_range = [
        i for i, fe in enumerate(time.get_finite_elements())
        if fe >= t_start and fe <= t_end
    ]
    t_in_range = [t for t in time if t >= t_start and t <= t_end]

    fe_in_range.pop(0)
    n_fe_in_range = len(fe_in_range)

    was_originally_active = get_activity_dict(model)
    was_originally_fixed = get_fixed_dict(model)

    # Deactivate model
    if not solve_initial_conditions:
        time_list = [t for t in time]
        deactivated = deactivate_model_at(model,
                                          time,
                                          time_list,
                                          outlvl=idaeslog.ERROR)
    else:
        time_list = [t for t in time if t != time.first()]
        deactivated = deactivate_model_at(model,
                                          time,
                                          time_list,
                                          outlvl=idaeslog.ERROR)

        assert degrees_of_freedom(model) == 0
        with idaeslog.solver_log(solver_log, level=idaeslog.DEBUG) as slc:
            results = solver.solve(model, tee=slc.tee)
        if results.solver.termination_condition == TerminationCondition.optimal:
            pass
        else:
            raise ValueError(
                'Failed to solve for consistent initial conditions.')

        deactivated[time.first()] = deactivate_model_at(
            model, time, time.first(), outlvl=idaeslog.ERROR)[time.first()]

    # "Integration" loop
    for i in fe_in_range:
        t_prev = time.at((i - 1) * ncp + 1)

        fe = [time.at(k) for k in range((i - 1) * ncp + 2, i * ncp + 2)]

        con_list = []
        for t in fe:
            # These will be fixed vars in constraints at t
            # Probably not necessary to record at what t
            # they occur
            for comp in deactivated[t]:
                if was_originally_active[id(comp)]:
                    comp.activate()
                    if not time_linking_vars:
                        if isinstance(comp, _ConstraintData):
                            con_list.append(comp)
                        elif isinstance(comp, _BlockData):
                            # Active here should be independent of whether block
                            # was active
                            con_list.extend(
                                list(
                                    comp.component_data_objects(Constraint,
                                                                active=True)))

        if not time_linking_vars:
            fixed_vars = []
            for con in con_list:
                for var in identify_variables(con.expr, include_fixed=False):
                    # use var_locator/ComponentMap to get index somehow
                    t_idx = get_implicit_index_of_set(var, time)
                    if t_idx is None:
                        assert not is_in_block_indexed_by(var, time)
                        continue
                    if t_idx <= t_prev:
                        fixed_vars.append(var)
                        var.fix()
        else:
            fixed_vars = []
            time_range = [
                t for t in time
                if t_prev - t <= max_linking_range and t <= t_prev
            ]
            time_range = [t_prev]
            for _slice in time_linking_vars:
                for t in time_range:
                    #if not _slice[t].fixed:
                    _slice[t].fix()
                    fixed_vars.append(_slice[t])

        # Here I assume that the only variables that can appear in
        # constraints at a different (later) time index are derivatives
        # and differential variables (they do so in the discretization
        # equations) and that they only participate at t_prev.
        #
        # This is not the case for, say, PID controllers, in which case
        # I should pass in a list of "complicating variables," then fix
        # them at all time points outside the finite element.
        #
        # Alternative solution is to identify_variables in each constraint
        # that is activated and fix those belonging to a previous finite
        # element. (Should not encounter variables belonging to a future
        # finite element.)
        # ^ This option is easier, less efficient
        #
        # In either case need to record whether variable was previously fixed
        # so I know if I should unfix it or not.

        for t in fe:
            for _slice in dae_vars:
                if not _slice[t].fixed:
                    # Fixed DAE variables are time-dependent disturbances,
                    # whose values should not be altered by this function.
                    _slice[t].set_value(_slice[t_prev].value)

        assert degrees_of_freedom(model) == 0

        with idaeslog.solver_log(solver_log, level=idaeslog.DEBUG) as slc:
            results = solver.solve(model, tee=slc.tee)
        if results.solver.termination_condition == TerminationCondition.optimal:
            pass
        else:
            raise ValueError('Failed to solve for finite element %s' % i)

        for t in fe:
            for comp in deactivated[t]:
                comp.deactivate()

        for var in fixed_vars:
            if not was_originally_fixed[id(var)]:
                var.unfix()

    for t in time:
        for comp in deactivated[t]:
            if was_originally_active[id(comp)]:
                comp.activate()
Example #3
0
def initialize(
    m,
    outlvl=idaeslog.NOTSET,
    optarg={
        "tol": 1e-6,
        "max_iter": 40,
    },
):
    """Initialize unit models"""
    init_log = idaeslog.getInitLogger(m.name, outlvl, tag="flowsheet")
    solve_log = idaeslog.getSolveLogger(m.name, outlvl, tag="flowsheet")

    solver = get_solver()
    solver.options = optarg
    init_log.info_low("Starting initialization...")

    if not os.path.exists("subcritical_boiler_init.json.gz"):
        # 10 Waterwalls, initial guess for specific simulation
        m.fs.Waterwalls[1].heat_fireside[:].fix(2.3e7)
        m.fs.Waterwalls[2].heat_fireside[:].fix(1.5e7)
        m.fs.Waterwalls[3].heat_fireside[:].fix(6.8e6)
        m.fs.Waterwalls[4].heat_fireside[:].fix(1.2e7)
        m.fs.Waterwalls[5].heat_fireside[:].fix(1.2e7)
        m.fs.Waterwalls[6].heat_fireside[:].fix(1.2e7)
        m.fs.Waterwalls[7].heat_fireside[:].fix(1.0e7)
        m.fs.Waterwalls[8].heat_fireside[:].fix(9.9e6)
        m.fs.Waterwalls[9].heat_fireside[:].fix(2.1)
        m.fs.Waterwalls[10].heat_fireside[:].fix(2.0e7)

        state_args_water_steam = {
            'flow_mol': 199470.7831,  # mol/s
            'pressure': 10903981.9107,  # Pa
            'enth_mol': 26585.3483
        }  # j/mol

        state_args_feedwater = {
            'flow_mol': 4630.6098,  # mol/s
            'pressure': 10903981.9107,  # Pa
            'enth_mol': 22723.907
        }  # j/mol

        m.fs.drum.initialize(
            outlvl=outlvl,
            optarg=solver.options,
            state_args_water_steam=state_args_water_steam,
            state_args_feedwater=state_args_feedwater,
        )
        m.fs.downcomer.inlet.flow_mol[:].fix(
            m.fs.drum.liquid_outlet.flow_mol[0].value)
        m.fs.downcomer.inlet.pressure[:].fix(
            m.fs.drum.liquid_outlet.pressure[0].value)
        m.fs.downcomer.inlet.enth_mol[:].fix(
            m.fs.drum.liquid_outlet.enth_mol[0].value)

        m.fs.downcomer.initialize(
            state_args={
                "flow_mol": m.fs.drum.liquid_outlet.flow_mol[0].value,
                "pressure": m.fs.drum.liquid_outlet.pressure[0].value,
                "enth_mol": m.fs.drum.liquid_outlet.enth_mol[0].value,
            },
            outlvl=outlvl,
            optarg=solver.options,
        )

        m.fs.Waterwalls[1].inlet.flow_mol[:].fix(
            m.fs.downcomer.outlet.flow_mol[0].value)
        m.fs.Waterwalls[1].inlet.pressure[:].fix(
            m.fs.downcomer.outlet.pressure[0].value)
        m.fs.Waterwalls[1].inlet.enth_mol[:].fix(
            m.fs.downcomer.outlet.enth_mol[0].value)
        m.fs.Waterwalls[1].initialize(
            state_args={
                "flow_mol": m.fs.Waterwalls[1].inlet.flow_mol[0].value,
                "pressure": m.fs.Waterwalls[1].inlet.pressure[0].value,
                "enth_mol": m.fs.Waterwalls[1].inlet.enth_mol[0].value,
            },
            outlvl=6,
            optarg=solver.options,
        )

        for i in range(2, 11):
            m.fs.Waterwalls[i].inlet.flow_mol[:].fix(
                m.fs.Waterwalls[i - 1].outlet.flow_mol[0].value)
            m.fs.Waterwalls[i].inlet.pressure[:].fix(
                m.fs.Waterwalls[i - 1].outlet.pressure[0].value)
            m.fs.Waterwalls[i].inlet.enth_mol[:].fix(
                m.fs.Waterwalls[i - 1].outlet.enth_mol[0].value)
            m.fs.Waterwalls[i].initialize(
                state_args={
                    "flow_mol":
                    m.fs.Waterwalls[i - 1].outlet.flow_mol[0].value,
                    "pressure":
                    m.fs.Waterwalls[i - 1].outlet.pressure[0].value,
                    "enth_mol":
                    m.fs.Waterwalls[i - 1].outlet.enth_mol[0].value,
                },
                outlvl=6,
                optarg=solver.options,
            )

        m.fs.drum.feedwater_inlet.flow_mol[:].fix()
        m.fs.drum.feedwater_inlet.pressure[:].unfix()
        m.fs.drum.feedwater_inlet.enth_mol[:].fix()

        m.fs.downcomer.inlet.flow_mol[:].unfix()
        m.fs.downcomer.inlet.pressure[:].unfix()
        m.fs.downcomer.inlet.enth_mol[:].unfix()
        print('solving full-space problem')
        for i in m.fs.ww_zones:
            m.fs.Waterwalls[i].inlet.flow_mol[:].unfix()
            m.fs.Waterwalls[i].inlet.pressure[:].unfix()
            m.fs.Waterwalls[i].inlet.enth_mol[:].unfix()

        df = degrees_of_freedom(m)
        if df != 0:
            raise ValueError("Check degrees of freedom: {}".format(df))
        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            print('solving full-space problem')
            res = solver.solve(m, tee=slc.tee)
        init_log.info_low("Initialization Complete: {}".format(
            idaeslog.condition(res)))
        ms.to_json(m, fname="subcritical_boiler_init.json.gz")
    else:
        print('\n\nInitializing from json file')
        ms.from_json(m, fname="subcritical_boiler_init.json.gz")
    return m
Example #4
0
def test_initialize():
    """Make a turbine model and make sure it doesn't throw exception"""
    m = build_turbine_for_run_test()
    turb = m.fs.turb

    # Set the inlet of the turbine
    p = 2.4233e7
    hin = pyo.value(iapws95.htpx(T=880*pyo.units.K, P=p*pyo.units.Pa))
    m.fs.turb.inlet_split.inlet.enth_mol[0].fix(hin)
    m.fs.turb.inlet_split.inlet.flow_mol[0].fix(26000)
    m.fs.turb.inlet_split.inlet.pressure[0].fix(p)

    # Set the inlet of the ip section, which is disconnected
    # here to insert reheater
    p = 7.802e+06
    hin = pyo.value(iapws95.htpx(T=880*pyo.units.K, P=p*pyo.units.Pa))
    m.fs.turb.ip_stages[1].inlet.enth_mol[0].value = hin
    m.fs.turb.ip_stages[1].inlet.flow_mol[0].value = 25220.0
    m.fs.turb.ip_stages[1].inlet.pressure[0].value = p

    for i, s in turb.hp_stages.items():
        s.ratioP[:] = 0.88
        s.efficiency_isentropic[:] = 0.9
    for i, s in turb.ip_stages.items():
        s.ratioP[:] = 0.85
        s.efficiency_isentropic[:] = 0.9
    for i, s in turb.lp_stages.items():
        s.ratioP[:] = 0.82
        s.efficiency_isentropic[:] = 0.9

    turb.hp_split[4].split_fraction[0,"outlet_2"].fix(0.03)
    turb.hp_split[7].split_fraction[0,"outlet_2"].fix(0.03)
    turb.ip_split[5].split_fraction[0,"outlet_2"].fix(0.04)
    turb.ip_split[14].split_fraction[0,"outlet_2"].fix(0.04)
    turb.ip_split[14].split_fraction[0,"outlet_3"].fix(0.15)
    turb.lp_split[4].split_fraction[0,"outlet_2"].fix(0.04)
    turb.lp_split[7].split_fraction[0,"outlet_2"].fix(0.04)
    turb.lp_split[9].split_fraction[0,"outlet_2"].fix(0.04)
    turb.lp_split[11].split_fraction[0,"outlet_2"].fix(0.04)

    # Congiure with reheater for a full test
    turb.ip_stages[1].inlet.fix()
    for i in turb.throttle_valve:
        turb.throttle_valve[i].Cv.fix()
        turb.throttle_valve[i].valve_opening.fix()
    turb.inlet_split.inlet.flow_mol.unfix()
    turb.inlet_mix.use_equal_pressure_constraint()

    iscale.calculate_scaling_factors(m)
    turb.initialize(outlvl=1)
    turb.ip_stages[1].inlet.unfix()


    for t in m.fs.time:
        m.fs.reheat.inlet.flow_mol[t].value = \
            pyo.value(turb.hp_split[7].outlet_1_state[t].flow_mol)
        m.fs.reheat.inlet.enth_mol[t].value = \
            pyo.value(turb.hp_split[7].outlet_1_state[t].enth_mol)
        m.fs.reheat.inlet.pressure[t].value = \
            pyo.value(turb.hp_split[7].outlet_1_state[t].pressure)
    m.fs.reheat.initialize(outlvl=4)
    def reheat_T_rule(b, t):
        return m.fs.reheat.control_volume.properties_out[t].temperature == 880
    m.fs.reheat.temperature_out_equation = pyo.Constraint(
            m.fs.reheat.flowsheet().config.time,
            rule=reheat_T_rule)

    pyo.TransformationFactory("network.expand_arcs").apply_to(m)
    m.fs.turb.outlet_stage.control_volume.properties_out[0].pressure.fix()

    assert degrees_of_freedom(m)==0
    solver.solve(m, tee=True)

    eq_cons = activated_equalities_generator(m)
    for c in eq_cons:
        assert abs(c.body() - c.lower) < 1e-4

    return m
Example #5
0
 def test_dof(self, sapon):
     assert degrees_of_freedom(sapon) == 0
Example #6
0
    def test_oc_conv(self):
        m = self._make_model()
        rxn_block = m.fs.reaction_block

        n_scen = 3
        mols = pyunits.mol / pyunits.s
        kgs = pyunits.kg / pyunits.s
        K = pyunits.K
        bar = pyunits.bar
        state_values = {
            "gas_state.flow_mol": [1.0 * mols] * n_scen,
            "solid_state.flow_mass": [1.0 * kgs] * n_scen,
            "gas_state.temperature": [1273.0 * K] * n_scen,
            "solid_state.temperature": [1273.0 * K] * n_scen,
            "gas_state.pressure": [1.0 * bar] * n_scen,
            "solid_state.particle_porosity": [0.27] * n_scen,
            "gas_state.mole_frac_comp[O2]": [0.25] * n_scen,
            "gas_state.mole_frac_comp[N2]": [0.25] * n_scen,
            "gas_state.mole_frac_comp[H2O]": [0.25] * n_scen,
            "gas_state.mole_frac_comp[CO2]": [0.25] * n_scen,
            "solid_state.mass_frac_comp[Fe2O3]": [2 / 3, 0.0, 1 / 3],
            "solid_state.mass_frac_comp[Fe3O4]": [0.0, 2 / 3, 1 / 3],
            "solid_state.mass_frac_comp[Al2O3]": [1 / 3] * n_scen,
        }
        state_values = ComponentMap((m.fs.find_component(name), values)
                                    for name, values in state_values.items())

        target_values = {
            "reaction_block.OC_conv": [
                1.0,
                0.0,
                0.4915,
            ],
            "reaction_block.OC_conv_temp": [
                2.005e-4,
                1.0,
                0.6371,
            ],
        }
        target_values = ComponentMap((m.fs.find_component(name), values)
                                     for name, values in target_values.items())

        assert degrees_of_freedom(m.fs) == 0

        param_sweeper = ParamSweeper(n_scen,
                                     state_values,
                                     output_values=target_values)
        with param_sweeper:
            for inputs, outputs in param_sweeper:
                solve_strongly_connected_components(m.fs)

                # Make sure property equalites have been converged
                assert number_large_residuals(m.fs, tol=1e-8) == 0

                # Sanity checks that inputs are properly set
                for var, val in inputs.items():
                    val = value(pyunits.convert(val, var.get_units()))
                    assert var.value == pytest.approx(value(val), abs=1e-3)

                # Make sure properties have been calculated as expected
                for var, val in outputs.items():
                    val = value(pyunits.convert(val, var.get_units()))
                    assert var.value == pytest.approx(value(val), abs=1e-3)
Example #7
0
    def initialize(self,
                   state_args={},
                   outlvl=0,
                   solver='ipopt',
                   optarg={
                       'tol': 1e-6,
                       'max_iter': 30
                   }):
        """
        Initialize the turbine stage model.  This deactivates the
        specialized constraints, then does the isentropic turbine initialization,
        then reactivates the constraints and solves.

        Args:
            state_args (dict): Initial state for property initialization
            outlvl (int): Amount of output (0 to 3) 0 is lowest
            solver (str): Solver to use for initialization
            optarg (dict): Solver arguments dictionary
        """
        stee = True if outlvl >= 3 else False
        # sp is what to save to make sure state after init is same as the start
        #   saves value, fixed, and active state, doesn't load originally free
        #   values, this makes sure original problem spec is same but initializes
        #   the values of free vars
        sp = StoreSpec.value_isfixed_isactive(only_fixed=True)
        istate = to_json(self, return_dict=True, wts=sp)

        self.deltaP[:].unfix()
        self.ratioP[:].unfix()

        # fix inlet and free outlet
        for t in self.flowsheet().config.time:
            for k, v in self.inlet.vars.items():
                v[t].fix()
            for k, v in self.outlet.vars.items():
                v[t].unfix()
            # to calculate outlet pressure
            Pout = self.outlet.pressure[t]
            Pin = self.inlet.pressure[t]
            if self.deltaP[t].value is not None:
                prdp = value((self.deltaP[t] - Pin) / Pin)
            else:
                prdp = -100  # crazy number to say don't use deltaP as guess
            if value(Pout / Pin) > 1 or value(Pout / Pin) < 0.0:
                if value(self.ratioP[t]) <= 1 and value(self.ratioP[t]) >= 0:
                    Pout.value = value(Pin * self.ratioP[t])
                elif prdp <= 1 and prdp >= 0:
                    Pout.value = value(prdp * Pin)
                else:
                    Pout.value = value(Pin * 0.95)
            self.deltaP[t] = value(Pout - Pin)
            self.ratioP[t] = value(Pout / Pin)

        # Make sure the initialization problem has no degrees of freedom
        # This shouldn't happen here unless there is a bug in this
        dof = degrees_of_freedom(self)
        try:
            assert (dof == 0)
        except:
            _log.exception("degrees_of_freedom = {}".format(dof))
            raise

        # one bad thing about reusing this is that the log messages aren't
        # really compatible with being nested inside another initialization
        super().initialize(state_args=state_args,
                           outlvl=outlvl,
                           solver=solver,
                           optarg=optarg)

        # reload original spec
        from_json(self, sd=istate, wts=sp)
Example #8
0
    def test_CV1D_w_inherent_rxns_comp_total(self, frame):
        frame.fs.cv = ControlVolume1DBlock(
            default={
                "property_package": frame.fs.params,
                "transformation_method": "dae.finite_difference",
                "transformation_scheme": "BACKWARD",
                "finite_elements": 2
            })

        frame.fs.cv.add_geometry()

        frame.fs.cv.add_state_blocks(has_phase_equilibrium=False)

        frame.fs.cv.add_material_balances(
            balance_type=MaterialBalanceType.componentTotal)

        frame.fs.cv.add_energy_balances()
        frame.fs.cv.add_momentum_balances()
        frame.fs.cv.apply_transformation()

        frame.fs.cv.properties[0, 0].flow_mol.fix(100)
        frame.fs.cv.properties[0, 0].mole_frac_comp.fix(0.25)
        frame.fs.cv.properties[0, 0].temperature.fix(350)
        frame.fs.cv.properties[0, 0].pressure.fix(101325)

        frame.fs.cv.area.fix(1)
        frame.fs.cv.length.fix(1)

        assert (degrees_of_freedom(frame)) == 0

        frame.fs.cv.initialize()

        solver = get_solver()

        results = solver.solve(frame)

        assert results.solver.termination_condition == \
            TerminationCondition.optimal
        assert results.solver.status == SolverStatus.ok

        assert value(frame.fs.cv.properties[0, 1].k_eq["e1"]) == 2

        assert (value(
            frame.fs.cv.properties[0, 1].k_eq["e1"]) == pytest.approx(
                value(frame.fs.cv.properties[0, 1].mole_frac_comp["b"] /
                      frame.fs.cv.properties[0, 1].mole_frac_comp["a"]),
                rel=1e-5))

        assert (value(
            frame.fs.cv.properties[0, 1].mole_frac_comp["a"]) == pytest.approx(
                1 / 6, rel=1e-5))
        assert (value(
            frame.fs.cv.properties[0, 1].mole_frac_comp["b"]) == pytest.approx(
                1 / 3, rel=1e-5))
        assert (value(
            frame.fs.cv.properties[0, 1].mole_frac_comp["c"]) == pytest.approx(
                1 / 4, rel=1e-5))
        assert (value(
            frame.fs.cv.properties[0, 1].mole_frac_comp["d"]) == pytest.approx(
                1 / 4, rel=1e-5))

        assert (value(frame.fs.cv.properties[0, 1].flow_mol) == pytest.approx(
            100, rel=1e-5))
        assert (value(frame.fs.cv.properties[0,
                                             1].temperature) == pytest.approx(
                                                 350, rel=1e-5))
        assert (value(frame.fs.cv.properties[0, 1].pressure) == pytest.approx(
            101325, rel=1e-5))
Example #9
0
def initialization_tester(m, dof=0, unit=None, **init_kwargs):
    """
    A method to test initialization methods on IDAES models. This method is
    designed to be used as part of the tests for most models.

    This method checks that the initialization methods runs as expceted
    and that the state of the model (active/deactive and fixed/unfixed)
    remains the same.

    This method also add some dummy constraitns to the model and deactivates
    them to make sure that the initialization does not affect their status.

    Args:
        m: a Concrete mdoel which contains a flowsheet and a model named unit
            (i.e. m.fs.unit) which will be initialized
        dof: expected degrees of freedom during initialization, default=0
        unit: unit object to test, if None assume m.fs.unit, default='None'
        init_kwargs: model specific arguments to pass to initialize method
                     (e.g. initial guesses for states)

    Returns:
        None

    Raises:
        AssertionErrors if an issue is found
    """
    if unit is None:
        unit = m.fs.unit
    # Add some extra constraints and deactivate them to make sure
    # they remain deactivated
    # Test both indexed and unindexed constraints
    unit.__dummy_var = Var()
    unit.__dummy_equality = Constraint(expr=unit.__dummy_var == 5)
    unit.__dummy_inequality = Constraint(expr=unit.__dummy_var <= 10)

    def deq_idx(b, i):
        return unit.__dummy_var == 5

    unit.__dummy_equality_idx = Constraint([1], rule=deq_idx)

    def dieq_idx(b, i):
        return unit.__dummy_var <= 10

    unit.__dummy_inequality_idx = Constraint([1], rule=dieq_idx)

    unit.__dummy_equality.deactivate()
    unit.__dummy_inequality.deactivate()
    unit.__dummy_equality_idx[1].deactivate()
    unit.__dummy_inequality_idx[1].deactivate()

    orig_fixed_vars = fixed_variables_set(m)
    orig_act_consts = activated_constraints_set(m)

    unit.initialize(**init_kwargs)

    assert degrees_of_freedom(m) == dof

    fin_fixed_vars = fixed_variables_set(m)
    fin_act_consts = activated_constraints_set(m)

    assert len(fin_act_consts) == len(orig_act_consts)
    assert len(fin_fixed_vars) == len(orig_fixed_vars)

    for c in fin_act_consts:
        assert c in orig_act_consts
    for v in fin_fixed_vars:
        assert v in orig_fixed_vars

    # Check dummy constraints and clean up
    assert not unit.__dummy_equality.active
    assert not unit.__dummy_inequality.active
    assert not unit.__dummy_equality_idx[1].active
    assert not unit.__dummy_inequality_idx[1].active

    unit.del_component(unit.__dummy_inequality)
    unit.del_component(unit.__dummy_equality)
    unit.del_component(unit.__dummy_inequality_idx)
    unit.del_component(unit.__dummy_equality_idx)
    unit.del_component(unit.__dummy_var)
Example #10
0
    def report(self, time_point=0, dof=False, ostream=None, prefix=""):

        time_point = float(time_point)

        if ostream is None:
            ostream = sys.stdout

        # Get DoF and model stats
        if dof:
            dof_stat = degrees_of_freedom(self)
            nv = number_variables(self)
            nc = number_activated_constraints(self)
            nb = number_activated_blocks(self)

        # Get components to report in performance section
        performance = self._get_performance_contents(time_point=time_point)

        # Get stream table
        stream_table = self._get_stream_table_contents(time_point=time_point)

        # Set model type output
        if hasattr(self, "is_flowsheet") and self.is_flowsheet:
            model_type = "Flowsheet"
        else:
            model_type = "Unit"

        # Write output
        max_str_length = 84
        tab = " " * 4
        ostream.write("\n" + "=" * max_str_length + "\n")

        lead_str = f"{prefix}{model_type} : {self.name}"
        trail_str = f"Time: {time_point}"
        mid_str = " " * (max_str_length - len(lead_str) - len(trail_str))
        ostream.write(lead_str + mid_str + trail_str)

        if dof:
            ostream.write("\n" + "=" * max_str_length + "\n")
            ostream.write(f"{prefix}{tab}Local Degrees of Freedom: {dof_stat}")
            ostream.write('\n')
            ostream.write(f"{prefix}{tab}Total Variables: {nv}{tab}"
                          f"Activated Constraints: {nc}{tab}"
                          f"Activated Blocks: {nb}")

        if performance is not None:
            ostream.write("\n" + "-" * max_str_length + "\n")
            ostream.write(f"{prefix}{tab}Unit Performance")
            ostream.write("\n" * 2)
            if "vars" in performance.keys() and len(performance["vars"]) > 0:
                ostream.write(f"{prefix}{tab}Variables: \n\n")

                tabular_writer(
                    ostream, prefix + tab,
                    ((k, v) for k, v in performance["vars"].items()),
                    ("Value", "Fixed", "Bounds"), lambda k, v:
                    ["{:#.5g}".format(value(v)), v.fixed, v.bounds])

            if "exprs" in performance.keys() and len(performance["exprs"]) > 0:
                ostream.write("\n")
                ostream.write(f"{prefix}{tab}Expressions: \n\n")

                tabular_writer(ostream, prefix + tab,
                               ((k, v)
                                for k, v in performance["exprs"].items()),
                               ("Value", ),
                               lambda k, v: ["{:#.5g}".format(value(v))])

            if ("params" in performance.keys()
                    and len(performance["params"]) > 0):
                ostream.write("\n")
                ostream.write(f"{prefix}{tab}Parameters: \n\n")

                tabular_writer(ostream, prefix + tab,
                               ((k, v)
                                for k, v in performance["params"].items()),
                               ("Value", "Mutable"),
                               lambda k, v: [value(v), not v.is_constant()])

        if stream_table is not None:
            ostream.write("\n" + "-" * max_str_length + "\n")
            ostream.write(f"{prefix}{tab}Stream Table")
            ostream.write('\n')
            ostream.write(
                textwrap.indent(stream_table_dataframe_to_string(stream_table),
                                prefix + tab))
        ostream.write("\n" + "=" * max_str_length + "\n")
Example #11
0
 def test_dof(self, frame):
     m = frame
     assert (degrees_of_freedom(m) == 0)
Example #12
0
    def initialize(self,
                   state_args_feed=None,
                   state_args_liq=None,
                   state_args_vap=None,
                   solver=None,
                   optarg=None,
                   outlvl=idaeslog.NOTSET):

        # TODO:
        # 1. Check initialization for dynamic mode. Currently not supported.
        # 2. Handle unfixed side split fraction vars
        # 3. Better logic to handle and fix state vars.

        init_log = idaeslog.getInitLogger(self.name, outlvl, tag="unit")
        solve_log = idaeslog.getSolveLogger(self.name, outlvl, tag="unit")

        init_log.info("Begin initialization.")

        if solver is None:
            init_log.warning("Solver not provided. Default solver(ipopt) "
                             " being used for initialization.")
            solver = get_default_solver()

        if self.config.has_liquid_side_draw:
            if not self.liq_side_sf.fixed:
                raise ConfigurationError(
                    "Liquid side draw split fraction not fixed but "
                    "has_liquid_side_draw set to True.")

        if self.config.has_vapor_side_draw:
            if not self.vap_side_sf.fixed:
                raise ConfigurationError(
                    "Vapor side draw split fraction not fixed but "
                    "has_vapor_side_draw set to True.")

        # Create initial guess if not provided by using current values
        if self.config.is_feed_tray and state_args_feed is None:
            state_args_feed = {}
            state_args_liq = {}
            state_args_vap = {}
            state_dict = (self.properties_in_feed[
                self.flowsheet().config.time.first()].define_port_members())

            for k in state_dict.keys():
                if "flow" in k:
                    if state_dict[k].is_indexed():
                        state_args_feed[k] = {}
                        state_args_liq[k] = {}
                        state_args_vap[k] = {}
                        for m in state_dict[k].keys():
                            state_args_feed[k][m] = \
                                state_dict[k][m].value
                            state_args_liq[k][m] = \
                                0.1 * state_dict[k][m].value
                            state_args_vap[k][m] = \
                                0.1 * state_dict[k][m].value

                    else:
                        state_args_feed[k] = state_dict[k].value
                        state_args_liq[k] = 0.1 * state_dict[k].value
                        state_args_vap[k] = 0.1 * state_dict[k].value
                else:
                    if state_dict[k].is_indexed():
                        state_args_feed[k] = {}
                        state_args_liq[k] = {}
                        state_args_vap[k] = {}
                        for m in state_dict[k].keys():
                            state_args_feed[k][m] = \
                                state_dict[k][m].value
                            state_args_liq[k][m] = \
                                state_dict[k][m].value
                            state_args_vap[k][m] = \
                                state_dict[k][m].value

                    else:
                        state_args_feed[k] = state_dict[k].value
                        state_args_liq[k] = state_dict[k].value
                        state_args_vap[k] = state_dict[k].value

        # Create initial guess if not provided by using current values
        if not self.config.is_feed_tray and state_args_liq is None:
            state_args_liq = {}
            state_dict = (self.properties_in_liq[
                self.flowsheet().config.time.first()].define_port_members())

            for k in state_dict.keys():
                if state_dict[k].is_indexed():
                    state_args_liq[k] = {}
                    for m in state_dict[k].keys():
                        state_args_liq[k][m] = state_dict[k][m].value
                else:
                    state_args_liq[k] = state_dict[k].value

        # Create initial guess if not provided by using current values
        if not self.config.is_feed_tray and state_args_vap is None:
            state_args_vap = {}
            state_dict = (self.properties_in_vap[
                self.flowsheet().config.time.first()].define_port_members())

            for k in state_dict.keys():
                if state_dict[k].is_indexed():
                    state_args_vap[k] = {}
                    for m in state_dict[k].keys():
                        state_args_vap[k][m] = state_dict[k][m].value
                else:
                    state_args_vap[k] = state_dict[k].value

        if self.config.is_feed_tray:
            feed_flags = self.properties_in_feed.initialize(
                outlvl=outlvl,
                solver=solver,
                optarg=optarg,
                hold_state=True,
                state_args=state_args_feed,
                state_vars_fixed=False)

        liq_in_flags = self.properties_in_liq. \
            initialize(outlvl=outlvl,
                       solver=solver,
                       optarg=optarg,
                       hold_state=True,
                       state_args=state_args_liq,
                       state_vars_fixed=False)

        vap_in_flags = self.properties_in_vap. \
            initialize(outlvl=outlvl,
                       solver=solver,
                       optarg=optarg,
                       hold_state=True,
                       state_args=state_args_vap,
                       state_vars_fixed=False)

        # state args to initialize the mixed outlet state block
        state_args_mixed = {}

        if self.config.is_feed_tray:

            # if feed tray, initialize the mixed state block at
            # the same condition.
            state_args_mixed = state_args_feed
        else:
            # if not feed tray, initialize mixed state block at average of
            # vap/liq inlets except pressure. While this is crude, it
            # will work for most combination of state vars.
            state_dict = (self.properties_in_liq[
                self.flowsheet().config.time.first()].define_port_members())
            for k in state_dict.keys():
                if k == "pressure":
                    # Take the lowest pressure and this is the liq inlet
                    state_args_mixed[k] = self.properties_in_liq[0].\
                        component(state_dict[k].local_name).value
                elif state_dict[k].is_indexed():
                    state_args_mixed[k] = {}
                    for m in state_dict[k].keys():
                        state_args_mixed[k][m] = \
                            0.5 * (self.properties_in_liq[0].
                                   component(state_dict[k].local_name)[m].
                                   value + self.properties_in_vap[0].
                                   component(state_dict[k].local_name)[m].
                                   value)
                else:
                    state_args_mixed[k] = \
                        0.5 * (self.properties_in_liq[0].
                               component(state_dict[k].local_name).value +
                               self.properties_in_vap[0].
                               component(state_dict[k].local_name).value)

        # Initialize the mixed outlet state block
        self.properties_out. \
            initialize(outlvl=outlvl,
                       solver=solver,
                       optarg=optarg,
                       hold_state=False,
                       state_args=state_args_mixed,
                       state_vars_fixed=False)

        # Deactivate energy balance
        self.enthalpy_mixing_equations.deactivate()

        # Try fixing the outlet temperature if else pass
        # NOTE: if passed then there would probably be a degree of freedom
        try:
            self.properties_out[:].temperature.\
                fix(state_args_mixed["temperature"])
        except AttributeError:
            init_log.warning("Trying to fix outlet temperature "
                             "during initialization but temperature attribute "
                             "unavailable in the state block. Initialization "
                             "proceeding with a potential degree of freedom.")

        # Deactivate pressure balance
        self.pressure_drop_equation.deactivate()

        # Try fixing the outlet temperature if else pass
        # NOTE: if passed then there would probably be a degree of freedom
        try:
            self.properties_out[:].pressure.\
                fix(state_args_mixed["pressure"])
        except AttributeError:
            init_log.warning("Trying to fix outlet pressure "
                             "during initialization but pressure attribute "
                             "unavailable in the state block. Initialization "
                             "proceeding with a potential degree of freedom.")

        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            res = solver.solve(self, tee=slc.tee)
        init_log.info("Mass balance solve {}.".format(idaeslog.condition(res)))

        # Activate energy balance
        self.enthalpy_mixing_equations.activate()
        try:
            self.properties_out[:].temperature.unfix()
        except AttributeError:
            pass

        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            res = solver.solve(self, tee=slc.tee)
        init_log.info("Mass and energy balance solve {}.".format(
            idaeslog.condition(res)))

        # Activate pressure balance
        self.pressure_drop_equation.activate()
        try:
            self.properties_out[:].pressure.unfix()
        except AttributeError:
            pass

        if degrees_of_freedom(self) == 0:
            with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
                res = solver.solve(self, tee=slc.tee)
            init_log.info("Mass, energy and pressure balance solve {}.".format(
                idaeslog.condition(res)))
        else:
            raise Exception("State vars fixed but degrees of freedom "
                            "for tray block is not zero during "
                            "initialization.")

        self.properties_in_liq.release_state(flags=liq_in_flags, outlvl=outlvl)
        self.properties_in_vap.release_state(flags=vap_in_flags, outlvl=outlvl)

        init_log.info("Initialization complete, status {}.".format(
            idaeslog.condition(res)))

        if self.config.is_feed_tray:
            return feed_flags
Example #13
0
    def initialize(
        self,
        state_args={},
        outlvl=idaeslog.NOTSET,
        solver="ipopt",
        optarg={
            "tol": 1e-6,
            "max_iter": 30
        },
    ):
        """
        Initialize the inlet turbine stage model.  This deactivates the
        specialized constraints, then does the isentropic turbine initialization,
        then reactivates the constraints and solves.

        Args:
            state_args (dict): Initial state for property initialization
            outlvl (int): Amount of output (0 to 3) 0 is lowest
            solver (str): Solver to use for initialization
            optarg (dict): Solver arguments dictionary
        """
        init_log = idaeslog.getInitLogger(self.name, outlvl, tag="unit")
        solve_log = idaeslog.getSolveLogger(self.name, outlvl, tag="unit")

        # sp is what to save to make sure state after init is same as the start
        #   saves value, fixed, and active state, doesn't load originally free
        #   values, this makes sure original problem spec is same but initializes
        #   the values of free vars
        sp = StoreSpec.value_isfixed_isactive(only_fixed=True)
        istate = to_json(self, return_dict=True, wts=sp)
        # Deactivate special constraints
        self.inlet_flow_constraint.deactivate()
        self.isentropic_enthalpy.deactivate()
        self.efficiency_correlation.deactivate()
        self.deltaP.unfix()
        self.ratioP.unfix()

        # Fix turbine parameters + eff_isen
        self.eff_nozzle.fix()
        self.blade_reaction.fix()
        self.flow_coeff.fix()
        self.blade_velocity.fix()

        # fix inlet and free outlet
        for t in self.flowsheet().config.time:
            for k, v in self.inlet.vars.items():
                v[t].fix()
            for k, v in self.outlet.vars.items():
                v[t].unfix()
            # If there isn't a good guess for efficeny or outlet pressure
            # provide something reasonable.
            eff = self.efficiency_isentropic[t]
            eff.fix(
                eff.value if value(eff) > 0.3 and value(eff) < 1.0 else 0.8)
            # for outlet pressure try outlet pressure, pressure ratio, delta P,
            # then if none of those look reasonable use a pressure ratio of 0.8
            # to calculate outlet pressure
            Pout = self.outlet.pressure[t]
            Pin = self.inlet.pressure[t]
            prdp = value((self.deltaP[t] - Pin) / Pin)
            if value(Pout / Pin) > 0.98 or value(Pout / Pin) < 0.3:
                if value(self.ratioP[t]) < 0.98 and value(
                        self.ratioP[t]) > 0.3:
                    Pout.fix(value(Pin * self.ratioP))
                elif prdp < 0.98 and prdp > 0.3:
                    Pout.fix(value(prdp * Pin))
                else:
                    Pout.fix(value(Pin * 0.8))
            else:
                Pout.fix()
        self.deltaP[:] = value(Pout - Pin)
        self.ratioP[:] = value(Pout / Pin)

        for t in self.flowsheet().config.time:
            self.properties_isentropic[t].pressure.value = value(
                self.outlet.pressure[t])
            self.properties_isentropic[t].flow_mol.value = value(
                self.inlet.flow_mol[t])
            self.properties_isentropic[t].enth_mol.value = value(
                self.inlet.enth_mol[t] * 0.95)
            self.outlet.flow_mol[t].value = value(self.inlet.flow_mol[t])
            self.outlet.enth_mol[t].value = value(self.inlet.enth_mol[t] *
                                                  0.95)

        # Make sure the initialization problem has no degrees of freedom
        # This shouldn't happen here unless there is a bug in this
        dof = degrees_of_freedom(self)
        try:
            assert dof == 0
        except:
            init_log.exception("degrees_of_freedom = {}".format(dof))
            raise

        # one bad thing about reusing this is that the log messages aren't
        # really compatible with being nested inside another initialization
        super().initialize(state_args=state_args,
                           outlvl=outlvl,
                           solver=solver,
                           optarg=optarg)

        # Free eff_isen and activate sepcial constarints
        self.efficiency_isentropic.unfix()
        self.outlet.pressure.unfix()
        self.inlet_flow_constraint.activate()
        self.isentropic_enthalpy.activate()
        self.efficiency_correlation.activate()

        slvr = SolverFactory(solver)
        slvr.options = optarg
        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            res = slvr.solve(self, tee=slc.tee)

        init_log.info("Initialization Complete: {}".format(
            idaeslog.condition(res)))

        # reload original spec
        from_json(self, sd=istate, wts=sp)
Example #14
0
 def test_dof(self, model):
     assert degrees_of_freedom(model) == 0
Example #15
0
def test_setInputs_reaction_block(rxn_prop):
    assert degrees_of_freedom(rxn_prop.fs.unit) == 0
Example #16
0
def test_steadystate_power_plant_build():
    # constructing and initializing dynamic power plant
    # not solving due to simulation time >20 min
    m = subcrit_plant.get_model(dynamic=False, init=False)
    assert m.dynamic is False
    assert degrees_of_freedom(m) == -5
Example #17
0
    def test_k_rxn(self):
        m = self._make_model()
        rxn_block = m.fs.reaction_block

        n_scen = 4
        mols = pyunits.mol / pyunits.s
        kgs = pyunits.kg / pyunits.s
        K = pyunits.K
        bar = pyunits.bar
        state_values = {
            "gas_state.flow_mol": [1.0 * mols] * n_scen,
            "solid_state.flow_mass": [1.0 * kgs] * n_scen,
            "gas_state.temperature":
            [1000.0 * K, 1100.0 * K, 1200.0 * K, 1300.0 * K],
            "solid_state.temperature":
            [1000.0 * K, 1100.0 * K, 1200.0 * K, 1300.0 * K],
            "gas_state.pressure": [1.0 * bar] * n_scen,
            "solid_state.particle_porosity": [0.27] * n_scen,
            "gas_state.mole_frac_comp[O2]": [0.25] * n_scen,
            "gas_state.mole_frac_comp[N2]": [0.25] * n_scen,
            "gas_state.mole_frac_comp[H2O]": [0.25] * n_scen,
            "gas_state.mole_frac_comp[CO2]": [0.25] * n_scen,
            "solid_state.mass_frac_comp[Fe2O3]": [1.0 / 3.0] * n_scen,
            "solid_state.mass_frac_comp[Fe3O4]": [1.0 / 3.0] * n_scen,
            "solid_state.mass_frac_comp[Al2O3]": [1.0 / 3.0] * n_scen,
        }
        state_values = ComponentMap((m.fs.find_component(name), values)
                                    for name, values in state_values.items())

        # Units of k_rxn are "non-physical" si units, chosen to be
        # consistent with the reaction rate rule.
        target_values = {
            "reaction_block.k_rxn[R1]": [
                5.7556e-5,
                6.7076e-5,
                7.6203e-5,
                8.4888e-5,
            ],
        }
        target_values = ComponentMap((m.fs.find_component(name), values)
                                     for name, values in target_values.items())

        assert degrees_of_freedom(m.fs) == 0

        param_sweeper = ParamSweeper(n_scen,
                                     state_values,
                                     output_values=target_values)
        with param_sweeper:
            for inputs, outputs in param_sweeper:
                solve_strongly_connected_components(m.fs)

                # Make sure property equalites have been converged
                assert number_large_residuals(m.fs, tol=1e-8) == 0

                # Sanity checks that inputs are properly set
                for var, val in inputs.items():
                    val = value(pyunits.convert(val, var.get_units()))
                    assert var.value == pytest.approx(value(val), rel=1e-3)

                # Make sure properties have been calculated as expected
                for var, val in outputs.items():
                    val = value(pyunits.convert(val, var.get_units()))
                    assert var.value == pytest.approx(value(val), rel=1e-3)
Example #18
0
def test_dynamic_steam_cycle():
    # constructing and initializing dynamic steam cycle flowsheet
    m = steam_cycle.get_model(dynamic=True)
    assert m.dynamic is True
    assert degrees_of_freedom(m) == 7
Example #19
0
    def test_reaction_rate(self):
        m = self._make_model()
        rxn_block = m.fs.reaction_block

        n_scen = 9
        mols = pyunits.mol / pyunits.s
        kgs = pyunits.kg / pyunits.s
        K = pyunits.K
        bar = pyunits.bar
        state_values = {
            "gas_state.flow_mol": [1.0 * mols] * n_scen,
            "solid_state.flow_mass": [1.0 * kgs] * n_scen,
            "gas_state.temperature": [1273.0 * K] * n_scen,
            "solid_state.temperature": [
                1273.0 * K,
                1273.0 * K,
                1273.0 * K,
                1273.0 * K,
                1273.0 * K,
                1273.0 * K,
                1100.0 * K,
                1200.0 * K,
                1300.0 * K,
            ],
            "gas_state.pressure": [1.0 * bar] * n_scen,
            "solid_state.particle_porosity": [0.27] * n_scen,
            "gas_state.mole_frac_comp[O2]": [
                1.0,
                0.7,
                0.0,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
            ],
            "gas_state.mole_frac_comp[N2]": [
                0.0,
                0.1,
                1 / 3,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
            ],
            "gas_state.mole_frac_comp[H2O]": [
                0.0,
                0.1,
                1 / 3,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
            ],
            "gas_state.mole_frac_comp[CO2]": [
                0.0,
                0.1,
                1 / 3,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
                0.25,
            ],
            "solid_state.mass_frac_comp[Fe2O3]": [
                1 / 3,
                1 / 3,
                1 / 3,
                2 / 3,
                0.0,
                1 / 3,
                1 / 3,
                1 / 3,
                1 / 3,
            ],
            "solid_state.mass_frac_comp[Fe3O4]": [
                1 / 3,
                1 / 3,
                1 / 3,
                0.0,
                2 / 3,
                1 / 3,
                1 / 3,
                1 / 3,
                1 / 3,
            ],
            "solid_state.mass_frac_comp[Al2O3]": [1 / 3] * n_scen,
        }
        state_values = ComponentMap((m.fs.find_component(name), values)
                                    for name, values in state_values.items())

        molm3s = pyunits.mol / pyunits.m**3 / pyunits.s
        target_values = {
            "reaction_block.reaction_rate[R1]": [
                351.367 * molm3s,
                245.957 * molm3s,
                0.0 * molm3s,
                0.0 * molm3s,
                271.731 * molm3s,
                87.842 * molm3s,
                71.344 * molm3s,
                81.051 * molm3s,
                90.288 * molm3s,
            ],
        }
        target_values = ComponentMap((m.fs.find_component(name), values)
                                     for name, values in target_values.items())

        assert degrees_of_freedom(m.fs) == 0

        param_sweeper = ParamSweeper(n_scen,
                                     state_values,
                                     output_values=target_values)
        with param_sweeper:
            for inputs, outputs in param_sweeper:
                solve_strongly_connected_components(m.fs)

                # Make sure property equalites have been converged
                assert number_large_residuals(m.fs, tol=1e-8) == 0

                # Sanity checks that inputs are properly set
                for var, val in inputs.items():
                    val = value(pyunits.convert(val, var.get_units()))
                    assert var.value == pytest.approx(value(val), abs=1e-3)

                # Make sure properties have been calculated as expected
                for var, val in outputs.items():
                    if value(val) != 0:
                        # To get around Pyomo issue #1627
                        val = value(pyunits.convert(val, var.get_units()))
                    assert var.value == pytest.approx(value(val), abs=1e-3)
Example #20
0
def test_subcritical_recyrculation_system():
    m = recyrc.main()
    assert degrees_of_freedom(m) == 0
Example #21
0
    def initialize(self,
                   state_args=None,
                   solver=None,
                   optarg=None,
                   outlvl=idaeslog.NOTSET):

        init_log = idaeslog.getInitLogger(self.name, outlvl, tag="unit")
        solve_log = idaeslog.getSolveLogger(self.name, outlvl, tag="unit")

        if solver is None:
            init_log.warning("Solver not provided. Default solver(ipopt) "
                             " being used for initialization.")
            solver = get_default_solver()

        # Initialize the inlet and outlet state blocks. Calling the state
        # blocks initialize methods directly so that custom set of state args
        # can be passed to the inlet and outlet state blocks as control_volume
        # initialize method initializes the state blocks with the same
        # state conditions.
        flags = self.control_volume.properties_in. \
            initialize(state_args=state_args,
                       solver=solver,
                       optarg=optarg,
                       outlvl=outlvl,
                       hold_state=True)

        # Initialize outlet state block at same conditions of inlet except
        # the temperature. Set the temperature to a temperature guess based
        # on the desired boilup_ratio.

        # Get index for bubble point temperature and and assume it
        # will have only a single phase equilibrium pair. This is to
        # support the generic property framework where the T_bubble
        # is indexed by the phases_in_equilibrium. In distillation,
        # the assumption is that there will only be a single pair
        # i.e. vap-liq.
        idx = next(
            iter(self.control_volume.properties_in[0].temperature_bubble))
        temp_guess = 0.5 * (
            value(self.control_volume.properties_in[0].temperature_dew[idx]) -
            value(self.control_volume.properties_in[0].
                  temperature_bubble[idx])) + \
            value(self.control_volume.properties_in[0].temperature_bubble[idx])

        state_args_outlet = {}
        state_dict_outlet = (self.control_volume.properties_in[
            self.flowsheet().config.time.first()].define_port_members())

        for k in state_dict_outlet.keys():
            if state_dict_outlet[k].is_indexed():
                state_args_outlet[k] = {}
                for m in state_dict_outlet[k].keys():
                    state_args_outlet[k][m] = value(state_dict_outlet[k][m])
            else:
                if k != "temperature":
                    state_args_outlet[k] = value(state_dict_outlet[k])
                else:
                    state_args_outlet[k] = temp_guess

        self.control_volume.properties_out.initialize(
            state_args=state_args_outlet,
            solver=solver,
            optarg=optarg,
            outlvl=outlvl,
            hold_state=False)

        if degrees_of_freedom(self) == 0:
            with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
                res = solver.solve(self, tee=slc.tee)
            init_log.info("Initialization Complete, {}.".format(
                idaeslog.condition(res)))
        else:
            raise ConfigurationError(
                "State vars fixed but degrees of freedom "
                "for reboiler is not zero during "
                "initialization. Please ensure that the boilup_ratio "
                "or the outlet temperature is fixed.")

        self.control_volume.properties_in.\
            release_state(flags=flags, outlvl=outlvl)
Example #22
0
def test_subcritical_boiler_dynamic_build():
    m = blr.get_model(dynamic=True, init=False)
    assert degrees_of_freedom(m) == 223
Example #23
0
 def test_dof(self, iapws):
     assert degrees_of_freedom(iapws) == 0
Example #24
0
def test_init(initialize_model):
    m, solver = initialize_model
    # check that the model solved properly and has 0 degrees of freedom
    assert (degrees_of_freedom(m) == 0)
    for c in activated_equalities_generator(m):
        assert (abs(c.body() - c.lower) < 1e-4)
Example #25
0
 def test_dof(self, btg):
     assert degrees_of_freedom(btg) == 0
Example #26
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)
    #    print(degrees_of_freedom(m))
    #    MS.to_json(m, fname = 'SCPC_full.json')
    #    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 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(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)
 def test_degrees_of_freedom(self, model):
     assert degrees_of_freedom(model.fs.unit) == 0
Example #28
0
def th(
    delta_temperature_callback=delta_temperature_underwood_tune_callback,
    tout_1=809.55,
    tout_2=788.53,
):
    m = ConcreteModel()
    m.fs = FlowsheetBlock(default={"dynamic": False})

    m.fs.properties = PhysicalParameterTestBlock()
    m.fs.prop_steam = iapws95.Iapws95ParameterBlock()
    m.fs.prop_fluegas = FlueGasParameterBlock()

    m.fs.unit = BoilerHeatExchanger(
        default={
            "delta_temperature_callback": delta_temperature_callback,
            "tube": {
                "property_package": m.fs.prop_steam
            },
            "shell": {
                "property_package": m.fs.prop_fluegas
            },
            "has_pressure_change": True,
            "has_holdup": False,
            "flow_pattern": HeatExchangerFlowPattern.countercurrent,
            "tube_arrangement": TubeArrangement.inLine,
            "side_1_water_phase": "Liq",
            "has_radiation": True,
        })

    #   Set inputs
    h = value(iapws95.htpx(773.15 * pyunits.K, 2.5449e7 * pyunits.Pa))
    m.fs.unit.side_1_inlet.flow_mol[0].fix(24678.26)  # mol/s
    m.fs.unit.side_1_inlet.enth_mol[0].fix(h)  # J/mol
    m.fs.unit.side_1_inlet.pressure[0].fix(2.5449e7)  # Pascals

    # FLUE GAS Inlet from Primary Superheater
    FGrate = 28.3876e3 * 0.18  # mol/s equivalent of ~1930.08 klb/hr
    # Use FG molar composition to set component flow rates (baseline report)
    m.fs.unit.side_2_inlet.flow_mol_comp[0, "H2O"].fix(FGrate * 8.69 / 100)
    m.fs.unit.side_2_inlet.flow_mol_comp[0, "CO2"].fix(FGrate * 14.49 / 100)
    m.fs.unit.side_2_inlet.flow_mol_comp[0, "N2"].fix(FGrate * 74.34 / 100)
    m.fs.unit.side_2_inlet.flow_mol_comp[0, "O2"].fix(FGrate * 2.47 / 100)
    m.fs.unit.side_2_inlet.flow_mol_comp[0, "NO"].fix(FGrate * 0.0006)
    m.fs.unit.side_2_inlet.flow_mol_comp[0, "SO2"].fix(FGrate * 0.002)
    m.fs.unit.side_2_inlet.temperature[0].fix(1102.335)
    m.fs.unit.side_2_inlet.pressure[0].fix(100145)

    # Primary Superheater
    ITM = 0.0254  # inch to meter conversion
    m.fs.unit.tube_di.fix((2.5 - 2 * 0.165) * ITM)
    m.fs.unit.tube_thickness.fix(0.165 * ITM)
    m.fs.unit.pitch_x.fix(3 * ITM)
    # gas path transverse width 54.78 ft / number of columns
    m.fs.unit.pitch_y.fix(54.78 / 108 * 12 * ITM)
    m.fs.unit.tube_length.fix(53.13 * 12 * ITM)
    m.fs.unit.tube_nrow.fix(20 * 2)
    m.fs.unit.tube_ncol.fix(108)
    m.fs.unit.nrow_inlet.fix(4)
    m.fs.unit.delta_elevation.fix(50)
    m.fs.unit.tube_r_fouling = 0.000176  # (0.001 h-ft^2-F/BTU)
    m.fs.unit.tube_r_fouling = 0.003131  # (0.03131 - 0.1779 h-ft^2-F/BTU)
    if m.fs.unit.config.has_radiation is True:
        m.fs.unit.emissivity_wall.fix(0.7)  # wall emissivity
    # correction factor for overall heat transfer coefficient
    m.fs.unit.fcorrection_htc.fix(1.5)
    # correction factor for pressure drop calc tube side
    m.fs.unit.fcorrection_dp_tube.fix(1.0)
    # correction factor for pressure drop calc shell side
    m.fs.unit.fcorrection_dp_shell.fix(1.0)

    assert degrees_of_freedom(m) == 0
    iscale.calculate_scaling_factors(m)
    m.fs.unit.initialize()

    results = solver.solve(m)
    # Check for optimal solution
    assert check_optimal_termination(results)
    assert value(
        m.fs.unit.side_1.properties_out[0].temperature) == pytest.approx(
            tout_1, abs=0.5)
    assert value(
        m.fs.unit.side_2.properties_out[0].temperature) == pytest.approx(
            tout_2, abs=0.5)
Example #29
0
    def initialize(blk,
                   state_args=None,
                   hold_state=False,
                   state_vars_fixed=False,
                   outlvl=idaeslog.NOTSET,
                   solver="ipopt",
                   optarg={"tol": 1e-8}):
        """
        Initialization routine for property package.
        Keyword Arguments:
            state_args : Dictionary with initial guesses for the state vars
                         chosen. Note that if this method is triggered
                         through the control volume, and if initial guesses
                         were not provided at the unit model level, the
                         control volume passes the inlet values as initial
                         guess.
                         Keys for the state_args dictionary are:
                         flow_mass, temperature, and mass_frac_comp
            outlvl : sets output level of initialization routine
            optarg : solver options dictionary object (default=None)
            solver : str indicating whcih solver to use during
                     initialization (default = "ipopt")
            hold_state : flag indicating whether the initialization routine
                         should unfix any state variables fixed during
                         initialization (default=False).
                         - True - states varaibles are not unfixed, and
                                 a dict of returned containing flags for
                                 which states were fixed during
                                 initialization.
                        - False - state variables are unfixed after
                                 initialization by calling the
                                 relase_state method
        Returns:
            If hold_states is True, returns a dict containing flags for
            which states were fixed during initialization.
        """
        init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="properties")
        solve_log = idaeslog.getSolveLogger(blk.name, outlvl, tag="properties")

        init_log.info_high('Starting initialization')

        # Deactivate the constraints specific for outlet block i.e.
        # when defined state is False
        for k in blk.keys():
            if blk[k].config.defined_state is False:
                blk[k].sum_component_eqn.deactivate()

        # Fix state variables if not already fixed
        if state_vars_fixed is False:
            flags = fix_state_vars(blk, state_args)
        else:
            # Check when the state vars are fixed already result in dof 0
            for k in blk.keys():
                if degrees_of_freedom(blk[k]) != 0:
                    raise Exception("State vars fixed but degrees of freedom "
                                    "for state block is not zero during "
                                    "initialization.")

        # ---------------------------------------------------------------------
        # Initialise values
        for k in blk.keys():
            if hasattr(blk[k], "density_skeletal_constraint"):
                calculate_variable_from_constraint(
                    blk[k].dens_mass_skeletal,
                    blk[k].density_skeletal_constraint)

            if hasattr(blk[k], "mixture_heat_capacity_eqn"):
                calculate_variable_from_constraint(
                    blk[k].cp_mass, blk[k].mixture_heat_capacity_eqn)

            if hasattr(blk[k], "mixture_enthalpy_eqn"):
                calculate_variable_from_constraint(blk[k].enth_mass,
                                                   blk[k].mixture_enthalpy_eqn)

            for j in blk[k]._params.component_list:

                if hasattr(blk[k], "cp_shomate_eqn"):
                    calculate_variable_from_constraint(
                        blk[k].cp_mol_comp[j], blk[k].cp_shomate_eqn[j])

                if hasattr(blk[k], "enthalpy_shomate_eqn"):
                    calculate_variable_from_constraint(
                        blk[k].enth_mol_comp[j],
                        blk[k].enthalpy_shomate_eqn[j])

        # Solve property block if non-empty
        free_vars = 0
        for k in blk.keys():
            free_vars += number_unfixed_variables_in_activated_equalities(
                blk[k])

        if free_vars > 0:
            # Create solver
            opt = get_solver(solver, optarg)
            with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
                res = solve_indexed_blocks(opt, [blk], tee=slc.tee)
        else:
            res = ""
        init_log.info_high("Initialization complete {}.".format(
            idaeslog.condition(res)))

        # ---------------------------------------------------------------------
        if state_vars_fixed is False:
            if hold_state is True:
                return flags
            else:
                blk.release_state(flags)
Example #30
0
def _test_add_noise_at_time():
    mod = make_model(horizon=2, ntfe=20)
    time = mod.fs.time
    t0 = time.first()
    assert degrees_of_freedom(mod) == 0

    scalar_vars, dae_vars = flatten_dae_components(mod.fs, time, Var)
    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'])
    ]

    for t in time:
        diff_vars[0][t].setlb(290)
        diff_vars[0][t].setub(310)
        for i in range(1, 5):
            diff_vars[i][t].setlb(0)
            diff_vars[i][t].setub(1)
            # Pretend this is mole fraction...

    assert diff_vars[0][0].value == 300
    for i in range(1, 5):
        assert diff_vars[i][0].value == 0.001

    copy_values_at_time(diff_vars, diff_vars, [t for t in time if t != t0], t0)

    for seed in [4, 8, 15, 16, 23, 42]:
        random.seed(seed)
        weights = [10, 0.001, 0.001, 0.001, 0.001]
        nom_vals = add_noise_at_time(diff_vars, 0, weights=weights)

        assert nom_vals[0][0] == 300
        assert diff_vars[0][0].value != 300
        assert diff_vars[0][0].value == approx(300, abs=2)
        for i in range(1, 5):
            assert nom_vals[0][i] == 0.001
            # ^ nom_vals indexed by time, then var-index. This is confusing,
            # might need to change (or only accept one time point at a time)
            assert diff_vars[i][0].value != 0.001
            assert diff_vars[i][0].value == approx(0.001, abs=2e-4)
            # Within four standard deviations should be a safe check

        for i in range(0, 5):
            diff_vars[i][0].set_value(nom_vals[0][i])
        # Reset and try again with new seed

    # Try providing function for uniform random
    rand_fcn = random.uniform

    random_arg_dict = {
        'range_list': [(295, 305), (0.001, 0.01), (0.001, 0.01), (0.001, 0.01),
                       (0.001, 0.01)]
    }

    def args_fcn(i, val, **kwargs):
        # args_fcn expects arguments like this
        range_list = kwargs.pop('range_list', None)
        return range_list[i]

    nom_vals = add_noise_at_time(diff_vars,
                                 0.5,
                                 random_function=rand_fcn,
                                 args_function=args_fcn,
                                 random_arg_dict=random_arg_dict)

    assert nom_vals[0.5][0] == 300
    assert diff_vars[0][0.5].value != 300
    assert 295 <= diff_vars[0][0.5].value <= 305
    for i in range(1, 5):
        assert nom_vals[0.5][i] == 0.001
        assert diff_vars[i][0.5].value != 0.001
        assert 0.001 <= diff_vars[i][0.5].value <= 0.01

    # Try to get some bound violations
    random_arg_dict = {
        'range_list': [(295, 305), (1, 2), (1, 2), (1, 2), (1, 2)]
    }

    nom_vals = add_noise_at_time(diff_vars,
                                 1,
                                 random_function=rand_fcn,
                                 args_function=args_fcn,
                                 random_arg_dict=random_arg_dict,
                                 bound_strategy='push',
                                 bound_push=0.01)

    for i in range(1, 5):
        assert diff_vars[i][1].value == 0.99

    random.seed(123)
    with pytest.raises(ValueError) as exc_test:
        # Large weights - one of these lower bounds should fail...
        nom_vals = add_noise_at_time(diff_vars,
                                     1.5,
                                     bound_strategy='discard',
                                     discard_limit=0,
                                     weights=[1, 1, 1, 1, 1],
                                     sig_0=0.05)