def test_default_solve(self, frame_stateblock): m = frame_stateblock # fix state variables fix_state_vars(m.fs.stream) # solve model opt = get_solver() results = opt.solve(m.fs.stream[0]) assert_optimal_termination(results) # check convergence # TODO: update this when IDAES API is updated to return solver status for initialize() self.check_constraint_status(m.fs.stream[0]) # check results for (v_name, ind), val in m._test_objs.default_solution.items(): var = getattr(m.fs.stream[0], v_name)[ind] # relative tolerance doesn't mean anything for 0-valued things if val == 0: if not pytest.approx(val, abs=1.0e-08) == value(var): raise PropertyValueError( "Variable {v_name} with index {ind} is expected to have a value of {val} +/- 1.0e-08, " "but it has a value of {val_t}. \nUpdate default_solution dict in the " "configure function that sets up the PropertyTestHarness" .format(v_name=v_name, ind=ind, val=val, val_t=value(var))) elif not pytest.approx(val, rel=1e-3) == value(var): raise PropertyValueError( "Variable {v_name} with index {ind} is expected to have a value of {val} +/- 0.1%, " "but it has a value of {val_t}. \nUpdate default_solution dict in the " "configure function that sets up the PropertyTestHarness". format(v_name=v_name, ind=ind, val=val, val_t=value(var)))
def initialize_system(m): prtrt = m.fs.pretreatment desal = m.fs.desalination psttrt = m.fs.posttreatment # initialize feed solve(m.fs.feed) # initialize pretreatment propagate_state(m.fs.s_feed) flags = fix_state_vars(prtrt.intake.properties) solve(prtrt) revert_state_vars(prtrt.intake.properties, flags) # initialize desalination propagate_state(m.fs.s_prtrt_tb) m.fs.tb_prtrt_desal.properties_out[0].flow_mass_phase_comp["Liq", "H2O"] = value( m.fs.tb_prtrt_desal.properties_in[0].flow_mass_comp["H2O"] ) m.fs.tb_prtrt_desal.properties_out[0].flow_mass_phase_comp["Liq", "TDS"] = value( m.fs.tb_prtrt_desal.properties_in[0].flow_mass_comp["tds"] ) desal.RO.feed_side.properties_in[0].flow_mass_phase_comp["Liq", "H2O"] = value( m.fs.feed.properties[0].flow_mass_comp["H2O"] ) desal.RO.feed_side.properties_in[0].flow_mass_phase_comp["Liq", "TDS"] = value( m.fs.feed.properties[0].flow_mass_comp["tds"] ) desal.RO.feed_side.properties_in[0].temperature = value( m.fs.tb_prtrt_desal.properties_out[0].temperature ) desal.RO.feed_side.properties_in[0].pressure = value( desal.P1.control_volume.properties_out[0].pressure ) desal.RO.initialize() propagate_state(m.fs.s_tb_desal) if m.erd_type == "pressure_exchanger": flags = fix_state_vars(desal.S1.mixed_state) solve(desal) revert_state_vars(desal.S1.mixed_state, flags) elif m.erd_type == "pump_as_turbine": flags = fix_state_vars(desal.P1.control_volume.properties_in) solve(desal) revert_state_vars(desal.P1.control_volume.properties_in, flags) # initialize posttreatment propagate_state(m.fs.s_desal_tb) m.fs.tb_desal_psttrt.properties_out[0].flow_mass_comp["H2O"] = value( m.fs.tb_desal_psttrt.properties_in[0].flow_mass_phase_comp["Liq", "H2O"] ) m.fs.tb_desal_psttrt.properties_out[0].flow_mass_comp["tds"] = value( m.fs.tb_desal_psttrt.properties_in[0].flow_mass_phase_comp["Liq", "TDS"] ) propagate_state(m.fs.s_tb_psttrt) flags = fix_state_vars(psttrt.storage_tank_2.properties) solve(psttrt) revert_state_vars(psttrt.storage_tank_2.properties, flags)
def test_fix_state_vars_guesses_mismatch_index(model): # Note that flow_mol_phase_comp is labled as compoennt_flow # in define_state_vars state_args = {"component_flow_phase": {("p1", "c1"): 1, ("p1", "c2"): 2, ("p2", "c1"): 3}, "pressure": 2e5, "temperature": 500} with pytest.raises(ConfigurationError): fix_state_vars(model.fs.sb, state_args)
def test_fix_state_vars_partial_guesses(model): # Note that flow_mol_phase_comp is labled as compoennt_flow # in define_state_vars state_args = { "component_flow_phase": { ("p1", "c1"): 1, ("p1", "c2"): 2, ("p2", "c1"): 3, ("p2", "c2"): 4 } } flags = fix_state_vars(model.fs.sb, state_args) assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].value == 1 assert model.fs.sb.flow_mol_phase_comp[("p1", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c2")].value == 2 assert model.fs.sb.flow_mol_phase_comp[("p2", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c1")].value == 3 assert model.fs.sb.flow_mol_phase_comp[("p2", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c2")].value == 4 assert model.fs.sb.pressure.fixed assert model.fs.sb.pressure.value == 1e5 assert model.fs.sb.temperature.fixed assert model.fs.sb.temperature.value == 300 assert not flags[None, "component_flow_phase", ("p1", "c1")] assert not flags[None, "component_flow_phase", ("p1", "c2")] assert not flags[None, "component_flow_phase", ("p2", "c1")] assert not flags[None, "component_flow_phase", ("p2", "c2")] assert not flags[None, "pressure", None] assert not flags[None, "temperature", None]
def test_fix_state_vars_fixed_no_guesses(model): # Note that flow_mol_phase_comp is labled as compoennt_flow # in define_state_vars model.fs.sb.flow_mol_phase_comp["p1", "c1"].fix(10) model.fs.sb.pressure.fix(1.5e5) flags = fix_state_vars(model.fs.sb) assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].value == 10 assert model.fs.sb.flow_mol_phase_comp[("p1", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c2")].value == 2 assert model.fs.sb.flow_mol_phase_comp[("p2", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c1")].value == 2 assert model.fs.sb.flow_mol_phase_comp[("p2", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c2")].value == 2 assert model.fs.sb.pressure.fixed assert model.fs.sb.pressure.value == 1.5e5 assert model.fs.sb.temperature.fixed assert model.fs.sb.temperature.value == 300 # Pressure and component_flow_phase[p1, c1] should be True assert flags[None, "component_flow_phase", ("p1", "c1")] assert not flags[None, "component_flow_phase", ("p1", "c2")] assert not flags[None, "component_flow_phase", ("p2", "c1")] assert not flags[None, "component_flow_phase", ("p2", "c2")] assert flags[None, "pressure", None] assert not flags[None, "temperature", None]
def test_revert_state_vars_guesses(model): # Note that flow_mol_phase_comp is labled as compoennt_flow # in define_state_vars state_args = { "component_flow_phase": { ("p1", "c1"): 1, ("p1", "c2"): 2, ("p2", "c1"): 3, ("p2", "c2"): 4 }, "pressure": 2e5, "temperature": 500 } flags = fix_state_vars(model.fs.sb, state_args) revert_state_vars(model.fs.sb, flags) assert not model.fs.sb.flow_mol_phase_comp[("p1", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].value == 1 assert not model.fs.sb.flow_mol_phase_comp[("p1", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c2")].value == 2 assert not model.fs.sb.flow_mol_phase_comp[("p2", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c1")].value == 3 assert not model.fs.sb.flow_mol_phase_comp[("p2", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c2")].value == 4 assert not model.fs.sb.pressure.fixed assert model.fs.sb.pressure.value == 2e5 assert not model.fs.sb.temperature.fixed assert model.fs.sb.temperature.value == 500
def test_revert_state_vars_fixed_guesses(model): # Note that flow_mol_phase_comp is labled as compoennt_flow # in define_state_vars model.fs.sb.flow_mol_phase_comp["p1", "c1"].fix(10) model.fs.sb.pressure.fix(1.5e5) state_args = { "component_flow_phase": { ("p1", "c1"): 1, ("p1", "c2"): 2, ("p2", "c1"): 3, ("p2", "c2"): 4 }, "pressure": 2e5, "temperature": 500 } flags = fix_state_vars(model.fs.sb, state_args) revert_state_vars(model.fs.sb, flags) # Pressure and componet_flow[p1, c1] should still be fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].value == 10 assert not model.fs.sb.flow_mol_phase_comp[("p1", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c2")].value == 2 assert not model.fs.sb.flow_mol_phase_comp[("p2", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c1")].value == 3 assert not model.fs.sb.flow_mol_phase_comp[("p2", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c2")].value == 4 assert model.fs.sb.pressure.fixed assert model.fs.sb.pressure.value == 1.5e5 assert not model.fs.sb.temperature.fixed assert model.fs.sb.temperature.value == 500
def calculate_chemical_scaling_factors(unit, thermo_params, rxn_params, state_args, output_jac=False): calculate_chemical_scaling_factors_for_equilibrium_log_reactions(unit, rxn_params) calculate_chemical_scaling_factors_for_energy_balances(unit) calculate_chemical_scaling_factors_for_material_balances(unit) flags = fix_state_vars(unit.control_volume.properties_out, state_args) revert_state_vars(unit.control_volume.properties_out, flags)
def initialize(blk, state_args_water_steam={}, outlvl=0, solver='ipopt', optarg={'tol': 1e-6}): ''' Drum 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 * 0 = no output (default) * 1 = return solver state for each step in routine * 2 = return solver state for each step in subroutines * 3 = include solver output infomation (tee=True) optarg : solver options dictionary object (default={'tol': 1e-6}) solver : str indicating whcih solver to use during initialization (default = 'ipopt') Returns: None ''' init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="unit") solve_log = idaeslog.getSolveLogger(blk.name, outlvl, tag="unit") opt = SolverFactory(solver) opt.options = optarg init_log.info_low("Starting initialization...") # fix FeedWater Inlet flags_fw = fix_state_vars(blk.mixed_state, state_args_water_steam) blk.mixed_state.initialize() # initialize outlet states for t in blk.flowsheet().config.time: blk.vap_state[t].flow_mol = value(blk.mixed_state[t].flow_mol * blk.mixed_state[t].vapor_frac) blk.vap_state[t].enth_mol = value( blk.mixed_state[t].enth_mol_phase["Vap"]) blk.vap_state[t].pressure = value(blk.mixed_state[t].pressure) blk.vap_state[t].vapor_frac = 1 blk.liq_state[t].flow_mol = value( blk.mixed_state[t].flow_mol * (1 - blk.mixed_state[t].vapor_frac)) blk.liq_state[t].enth_mol = value( blk.mixed_state[t].enth_mol_phase["Liq"]) blk.liq_state[t].pressure = value(blk.mixed_state[t].pressure) blk.liq_state[t].vapor_frac = 0 # unfix variables revert_state_vars(blk.mixed_state, flags_fw) init_log.info_low("Initialization Complete.")
def test_revert_state_vars_basic(model): flags = fix_state_vars(model.fs.sb) revert_state_vars(model.fs.sb, flags) for i in model.fs.sb.flow_mol_phase_comp: assert not model.fs.sb.flow_mol_phase_comp[i].fixed assert model.fs.sb.flow_mol_phase_comp[i].value == 2 assert not model.fs.sb.pressure.fixed assert model.fs.sb.pressure.value == 1e5 assert not model.fs.sb.temperature.fixed assert model.fs.sb.temperature.value == 300
def initialize(blk, state_args_water_steam=None, outlvl=idaeslog.NOTSET, solver=None, optarg=None): ''' Drum initialization routine. Keyword Arguments: state_args_water_steam : 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") init_log.info_low("Starting initialization...") # fix FeedWater Inlet flags_fw = fix_state_vars(blk.mixed_state, state_args_water_steam) blk.mixed_state.initialize(solver=solver, optarg=optarg, outlvl=outlvl) # initialize outlet states for t in blk.flowsheet().time: blk.vap_state[t].flow_mol = value(blk.mixed_state[t].flow_mol * blk.mixed_state[t].vapor_frac) blk.vap_state[t].enth_mol = value( blk.mixed_state[t].enth_mol_phase["Vap"]) blk.vap_state[t].pressure = value(blk.mixed_state[t].pressure) blk.vap_state[t].vapor_frac = 1 blk.liq_state[t].flow_mol = value( blk.mixed_state[t].flow_mol * (1 - blk.mixed_state[t].vapor_frac)) blk.liq_state[t].enth_mol = value( blk.mixed_state[t].enth_mol_phase["Liq"]) blk.liq_state[t].pressure = value(blk.mixed_state[t].pressure) blk.liq_state[t].vapor_frac = 0 # unfix variables revert_state_vars(blk.mixed_state, flags_fw) init_log.info_low("Initialization Complete.")
def test_fix_state_vars_basic(model): flags = fix_state_vars(model.fs.sb) for i in model.fs.sb.flow_mol_phase_comp: assert model.fs.sb.flow_mol_phase_comp[i].fixed assert model.fs.sb.flow_mol_phase_comp[i].value == 2 assert model.fs.sb.pressure.fixed assert model.fs.sb.pressure.value == 1e5 assert model.fs.sb.temperature.fixed assert model.fs.sb.temperature.value == 300 assert not flags[None, "component_flow_phase", ("p1", "c1")] assert not flags[None, "component_flow_phase", ("p1", "c2")] assert not flags[None, "component_flow_phase", ("p2", "c1")] assert not flags[None, "component_flow_phase", ("p2", "c2")] assert not flags[None, "pressure", None] assert not flags[None, "temperature", None]
def calculate_RO_area(unit=None, water_recovery=0.5, solver=None): """ determine RO membrane area required to achieve the specified water recovery: unit: the RO unit model, e.g. m.fs.RO, it should have its inlet feed state block initiated to the correct values (default=None) water_recovery: the mass-based fraction of inlet H2O that becomes permeate (default=0.5) solver: solver object to be used (default=None) """ # fix inlet conditions flags = fix_state_vars(unit.feed_side.properties_in) # fix unit water recovery unit.feed_side.properties_out[0].flow_mass_phase_comp['Liq', 'H2O'].fix( unit.feed_side.properties_in[0].flow_mass_phase_comp['Liq', 'H2O'].value * (1 - water_recovery)) # solve for unit area check_dof(unit) solve(unit, solver=solver) # unfix variables revert_state_vars(unit.feed_side.properties_in, flags) unit.feed_side.properties_out[0].flow_mass_phase_comp['Liq', 'H2O'].unfix() return unit.area.value
def test_revert_state_vars_fixed_no_guesses(model): # Note that flow_mol_phase_comp is labled as compoennt_flow # in define_state_vars model.fs.sb.flow_mol_phase_comp["p1", "c1"].fix(10) model.fs.sb.pressure.fix(1.5e5) flags = fix_state_vars(model.fs.sb) revert_state_vars(model.fs.sb, flags) # Pressure and componet_flow[p1, c1] should still be fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c1")].value == 10 assert not model.fs.sb.flow_mol_phase_comp[("p1", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p1", "c2")].value == 2 assert not model.fs.sb.flow_mol_phase_comp[("p2", "c1")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c1")].value == 2 assert not model.fs.sb.flow_mol_phase_comp[("p2", "c2")].fixed assert model.fs.sb.flow_mol_phase_comp[("p2", "c2")].value == 2 assert model.fs.sb.pressure.fixed assert model.fs.sb.pressure.value == 1.5e5 assert not model.fs.sb.temperature.fixed assert model.fs.sb.temperature.value == 300
def initialize(blk, state_args={}, state_vars_fixed=False, hold_state=False, outlvl=idaeslog.NOTSET, solver='ipopt', optarg={'tol': 1e-8}): """ Initialization routine for property package. Keyword Arguments: state_args : a dict of initial values for the state variables defined by the property package. outlvl : sets output level of initialization routine optarg : solver options dictionary object (default=None) state_vars_fixed: Flag to denote if state vars have already been fixed. - True - states have already been fixed by the control volume 1D. Control volume 0D does not fix the state vars, so will be False if this state block is used with 0D blocks. - False - states have not been fixed. The state block will deal with fixing/unfixing. solver : str indicating which 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 variables 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('Starting initialization') for k in blk.keys(): # Deactivate the constraints specific for outlet block i.e. # when defined state is False if blk[k].config.defined_state is False: try: blk[k].sum_mole_frac_out.deactivate() except AttributeError: pass # Fix state variables if not already fixed if state_vars_fixed is False: flag_dict = fix_state_vars(blk, state_args) # Confirm DoF for sanity for k in blk.keys(): if degrees_of_freedom(blk[k]) != 0: raise BurntToast("Degrees of freedom were not zero " "after trying to fix state variables. " "Something broke in the generic property " "package code - please inform the IDAES " "developers.") else: # When state vars are fixed, check that DoF is 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.") # Set solver options if optarg is None: sopt = {'tol': 1e-8} else: sopt = optarg opt = SolverFactory('ipopt') opt.options = sopt # --------------------------------------------------------------------- # If present, initialize bubble and dew point calculations for k in blk.keys(): # Bubble temperature initialization if hasattr(blk[k], "_mole_frac_tbub"): # Use lowest component critical temperature as starting point # Starting high and moving down generally works better, # as it under-predicts next step due to exponential form of # Psat. # Subtract 1 to avoid potential singularities at Tcrit Tbub0 = min(blk[k]._params.temperature_crit_comp[j] for j in blk[k]._params.component_list) - 1 err = 1 counter = 0 # Newton solver with step limiter to prevent overshoot # Tolerance only needs to be ~1e-1 # Iteration limit of 30 while err > 1e-1 and counter < 30: f = value( sum(blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, Tbub0) * blk[k].mole_frac_comp[j] for j in blk[k]._params.component_list) - blk[k].pressure) df = value( sum(blk[k].mole_frac_comp[j] * blk[k]._params.config.pressure_sat_comp. pressure_sat_comp_dT(blk[k], j, Tbub0) for j in blk[k]._params.component_list)) # Limit temperature step to avoid excessive overshoot # Only limit positive steps due to non-linearity if f / df < -50: Tbub1 = Tbub0 + 50 else: Tbub1 = Tbub0 - f / df err = abs(Tbub1 - Tbub0) Tbub0 = Tbub1 counter += 1 blk[k].temperature_bubble.value = Tbub0 for j in blk[k]._params.component_list: blk[k]._mole_frac_tbub[j].value = value( blk[k].mole_frac_comp[j] * blk[k].pressure / blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, Tbub0)) # Bubble temperature initialization if hasattr(blk[k], "_mole_frac_tdew"): if hasattr(blk[k], "_mole_frac_tbub"): # If Tbub has been calculated above, use this as the # starting point Tdew0 = blk[k].temperature_bubble.value else: # Otherwise, use lowest component critical temperature as # starting point # Subtract 1 to avoid potential singularities at Tcrit Tdew0 = min(blk[k]._params.temperature_crit_comp[j] for j in blk[k]._params.component_list) - 1 err = 1 counter = 0 # Newton solver with step limiter to prevent overshoot # Tolerance only needs to be ~1e-1 # Iteration limit of 30 while err > 1e-1 and counter < 30: f = value(blk[k].pressure * sum( blk[k].mole_frac_comp[j] / blk[k]._params.config. pressure_sat_comp.pressure_sat_comp(blk[k], j, Tdew0) for j in blk[k]._params.component_list) - 1) df = -value(blk[k].pressure * sum(blk[k].mole_frac_comp[j] / blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, Tdew0)**2 * blk[k]._params.config.pressure_sat_comp. pressure_sat_comp_dT(blk[k], j, Tdew0) for j in blk[k]._params.component_list)) # Limit temperature step to avoid excessive overshoot if f / df < -50: Tdew1 = Tdew0 + 50 else: Tdew1 = Tdew0 - f / df err = abs(Tdew1 - Tdew0) Tdew0 = Tdew1 counter += 1 blk[k].temperature_dew.value = Tdew0 for j in blk[k]._params.component_list: blk[k]._mole_frac_tdew[j].value = value( blk[k].mole_frac_comp[j] * blk[k].pressure / blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, Tdew0)) # Bubble pressure initialization if hasattr(blk[k], "_mole_frac_pbub"): blk[k].pressure_bubble.value = value( sum(blk[k].mole_frac_comp[j] * blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, blk[k].temperature) for j in blk[k]._params.component_list)) for j in blk[k]._params.component_list: blk[k]._mole_frac_pbub[j].value = value( blk[k].mole_frac_comp[j] * blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, blk[k].temperature) / blk[k].pressure_bubble) # Dew pressure initialization if hasattr(blk[k], "_mole_frac_pdew"): blk[k].pressure_dew.value = value( sum(1 / (blk[k].mole_frac_comp[j] / blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, blk[k].temperature)) for j in blk[k]._params.component_list)) for j in blk[k]._params.component_list: blk[k]._mole_frac_pdew[j].value = value( blk[k].mole_frac_comp[j] * blk[k].pressure_bubble / blk[k]._params.config.pressure_sat_comp. pressure_sat_comp(blk[k], j, blk[k].temperature)) # Solve bubble and dew point constraints for c in blk[k].component_objects(Constraint): # Deactivate all constraints not associated wtih bubble and dew # points if c.local_name not in ("eq_pressure_dew", "eq_pressure_bubble", "eq_temperature_dew", "eq_temperature_bubble", "_sum_mole_frac_tbub", "_sum_mole_frac_tdew", "_sum_mole_frac_pbub", "_sum_mole_frac_pdew"): c.deactivate() # If StateBlock has active constraints (i.e. has bubble and/or dew # point calculations), solve the block to converge these n_cons = 0 for k in blk: n_cons += number_activated_constraints(blk[k]) if n_cons > 0: with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = solve_indexed_blocks(opt, [blk], tee=slc.tee) init_log.info("Dew and bubble point initialization: {}.".format( idaeslog.condition(res))) # --------------------------------------------------------------------- # If StateBlock is using a smooth VLE, calculate _T1 and _Teq eq_check = 0 for k in blk.keys(): if hasattr(blk[k], "_t1"): blk[k]._t1.value = max(blk[k].temperature.value, blk[k].temperature_bubble.value) blk[k]._teq.value = min(blk[k]._t1.value, blk[k].temperature_dew.value) eq_check += 1 if eq_check > 0: init_log.info("Equilibrium temperature initialization completed.") # --------------------------------------------------------------------- # Initialize flow rates and compositions for k in blk.keys(): blk[k]._params.config.state_definition.state_initialization(blk[k]) if outlvl > 0: init_log.info("State variable initialization completed.") # --------------------------------------------------------------------- if (blk[k]._params.config.phase_equilibrium_formulation is not None and (not blk[k].config.defined_state or blk[k].always_flash)): blk[k]._params.config.phase_equilibrium_formulation \ .phase_equil_initialization(blk[k]) with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = solve_indexed_blocks(opt, [blk], tee=slc.tee) init_log.info("Phase equilibrium initialization: {}.".format( idaeslog.condition(res))) # --------------------------------------------------------------------- # Initialize other properties for k in blk.keys(): for c in blk[k].component_objects(Constraint): # Activate all constraints except flagged do_not_initialize if c.local_name not in (blk[k]._params.config.state_definition. do_not_initialize): c.activate() with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = solve_indexed_blocks(opt, [blk], tee=slc.tee) init_log.info("Property initialization: {}.".format( idaeslog.condition(res))) # --------------------------------------------------------------------- # Return constraints to initial state for k in blk.keys(): for c in blk[k].component_objects(Constraint): if c.local_name in (blk[k]._params.config.state_definition. do_not_initialize): c.activate() if state_vars_fixed is False: if hold_state is True: return flag_dict else: blk.release_state(flag_dict) init_log.info("Property package initialization: {}.".format( idaeslog.condition(res)))
def initialize(blk, state_args=None, hold_state=False, outlvl=0, solver='ipopt', optarg={'tol': 1e-8}): """ Initialisation 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 provied at the unit model level, the control volume passes the inlet values as initial guess.The keys for the state_args dictionary are: flow_mol : value at which to initialize component flows pressure : value at which to initialize pressure temperature : value at which to initialize temperature mole_frac_comp: value at which to initialize the component mixture mole fraction outlvl : sets output level of initialisation routine * 0 = no output (default) * 1 = return solver state for each step in routine * 2 = include solver output infomation (tee=True) 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. """ # Fix state variables if not already fixed flags = fix_state_vars(blk, state_args) # Set solver options if outlvl > 1: stee = True else: stee = False if optarg is None: sopt = {'tol': 1e-8} else: sopt = optarg opt = SolverFactory('ipopt') opt.options = sopt # --------------------------------------------------------------------- for k in blk.keys(): blk[k].eq_total.deactivate() blk[k].eq_comp.deactivate() if (blk[k].config.defined_state is False): blk[k].eq_mol_frac_out.deactivate() if (blk[k].config.has_phase_equilibrium) or \ (blk[k].config.parameters.config.valid_phase == ('Liq', 'Vap')) or \ (blk[k].config.parameters.config.valid_phase == ('Vap', 'Liq')): blk[k].eq_Keq.deactivate() blk[k].eq_sum_mol_frac.deactivate() if (blk[k].config.has_phase_equilibrium) or \ (blk[k].config.parameters.config.valid_phase == ('Liq', 'Vap')) or \ (blk[k].config.parameters.config.valid_phase == ('Vap', 'Liq')): results = solve_indexed_blocks(opt, [blk], tee=stee) if outlvl > 0: if results.solver.termination_condition \ == TerminationCondition.optimal: _log.info("Initialisation step 1 for " "{} completed".format(blk.name)) else: _log.warning("Initialisation step 1 for " "{} failed".format(blk.name)) else: if outlvl > 0: _log.info("Initialisation step 1 for " "{} skipped".format(blk.name)) for k in blk.keys(): blk[k].eq_total.activate() blk[k].eq_comp.activate() if (blk[k].config.has_phase_equilibrium) or \ (blk[k].config.parameters.config.valid_phase == ('Liq', 'Vap')) or \ (blk[k].config.parameters.config.valid_phase == ('Vap', 'Liq')): blk[k].eq_Keq.activate() blk[k].eq_sum_mol_frac.activate() results = solve_indexed_blocks(opt, [blk], tee=stee) if outlvl > 0: if results.solver.termination_condition \ == TerminationCondition.optimal: _log.info("Initialisation step 2 for " "{} completed".format(blk.name)) else: _log.warning("Initialisation step 2 for " "{} failed".format(blk.name)) for k in blk.keys(): if (blk[k].config.defined_state is False): blk[k].eq_mol_frac_out.activate() # --------------------------------------------------------------------- # If input block, return flags, else release state if hold_state is True: return flags else: blk.release_state(flags) if outlvl > 0: if outlvl > 0: _log.info('{} Initialisation Complete.'.format(blk.name))
def initialize(blk, state_args=None, state_vars_fixed=False, hold_state=False, outlvl=1, 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 provied at the unit model level, the control volume passes the inlet values as initial guess.The keys for the state_args dictionary are: flow_mol : value at which to initialize component flows pressure : value at which to initialize pressure temperature : value at which to initialize temperature mole_frac_comp: value at which to initialize the component mixture mole fraction outlvl : sets output level of initialization routine * 0 = no output (default) * 1 = return solver state for each step in routine * 2 = include solver output infomation (tee=True) optarg : solver options dictionary object (default=None) state_vars_fixed: Flag to denote if state vars have already been fixed. - True - states have already been fixed by the control volume 1D. Control volume 0D does not fix the state vars, so will be False if this state block is used with 0D blocks. - False - states have not been fixed. The state block will deal with fixing/unfixing. 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. """ _log.info('Starting {} initialization'.format(blk.name)) # 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_mole_frac_out.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.") # Set solver options if outlvl > 1: stee = True else: stee = False if optarg is None: sopt = {'tol': 1e-8} else: sopt = optarg opt = SolverFactory('ipopt') opt.options = sopt # --------------------------------------------------------------------- # If present, initialize bubble and dew point calculations for k in blk.keys(): if hasattr(blk[k], "eq_temperature_bubble"): calculate_variable_from_constraint( blk[k].temperature_bubble, blk[k].eq_temperature_bubble) if hasattr(blk[k], "eq_temperature_dew"): calculate_variable_from_constraint(blk[k].temperature_dew, blk[k].eq_temperature_dew) if hasattr(blk[k], "eq_pressure_bubble"): calculate_variable_from_constraint(blk[k].pressure_bubble, blk[k].eq_pressure_bubble) if hasattr(blk[k], "eq_pressure_dew"): calculate_variable_from_constraint(blk[k].pressure_dew, blk[k].eq_pressure_dew) if outlvl > 0: _log.info("Dew and bubble points initialization for " "{} completed".format(blk.name)) # --------------------------------------------------------------------- # If flash, initialize T1 and Teq for k in blk.keys(): if blk[k].config.has_phase_equilibrium: blk[k]._t1.value = max(blk[k].temperature.value, blk[k].temperature_bubble.value) blk[k]._teq.value = min(blk[k]._t1.value, blk[k].temperature_dew.value) if outlvl > 0: _log.info("Equilibrium temperature initialization for " "{} completed".format(blk.name)) # --------------------------------------------------------------------- # Initialize flow rates and compositions # TODO : This will need ot be generalised more when we move to a # modular implementation for k in blk.keys(): if blk[k]._params.config.valid_phase == "Liq": blk[k].flow_mol_phase['Liq'].value = \ blk[k].flow_mol.value for j in blk[k]._params.component_list: blk[k].mole_frac_phase_comp['Liq', j].value = \ blk[k].mole_frac_comp[j].value elif blk[k]._params.config.valid_phase == "Vap": blk[k].flow_mol_phase['Vap'].value = \ blk[k].flow_mol.value for j in blk[k]._params.component_list: blk[k].mole_frac_phase_comp['Vap', j].value = \ blk[k].mole_frac_comp[j].value else: # Seems to work best with default values for phase flows for j in blk[k]._params.component_list: blk[k].mole_frac_phase_comp['Vap', j].value = \ blk[k].mole_frac_comp[j].value blk[k].mole_frac_phase_comp['Liq', j].value = \ blk[k].mole_frac_comp[j].value calculate_variable_from_constraint( blk[k].pressure_sat[j], blk[k].eq_pressure_sat[j]) # --------------------------------------------------------------------- # Solve phase equilibrium constraints for k in blk.keys(): for c in blk[k].component_objects(Constraint): # Deactivate all property constraints if c.local_name not in ("total_flow_balance", "component_flow_balances", "equilibrium_constraint", "sum_mole_frac", "_t1_constraint", "_teq_constraint", "eq_pressure_dew", "eq_pressure_bubble", "eq_temperature_dew", "eq_temperature_bubble", "eq_pressure_sat"): c.deactivate() results = solve_indexed_blocks(opt, [blk], tee=stee) if outlvl > 0: if results.solver.termination_condition \ == TerminationCondition.optimal: _log.info("Phase state initialization for " "{} completed".format(blk.name)) else: _log.warning("Phase state initialization for " "{} failed".format(blk.name)) # --------------------------------------------------------------------- # Initialize other properties for k in blk.keys(): for c in blk[k].component_objects(Constraint): # Activate all constraints except sum_mole_frac_out if c.local_name not in ("sum_mole_frac_out"): c.activate() if outlvl > 0: if results.solver.termination_condition \ == TerminationCondition.optimal: _log.info("Property initialization for " "{} completed".format(blk.name)) else: _log.warning("Property initialization for " "{} failed".format(blk.name)) # --------------------------------------------------------------------- # Return state to initial conditions for k in blk.keys(): if (blk[k].config.defined_state is False): blk[k].sum_mole_frac_out.activate() if state_vars_fixed is False: if hold_state is True: return flags else: blk.release_state(flags) if outlvl > 0: _log.info("Initialization completed for {}".format(blk.name))
def initialize(self, state_args={}, state_vars_fixed=False, hold_state=False, outlvl=idaeslog.NOTSET, temperature_bounds=(260, 616), solver=None, optarg=None): ''' 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 provied at the unit model level, the control volume passes the inlet values as initial guess.The keys for the state_args dictionary are: flow_mol_comp : value at which to initialize component flows (default=None) pressure : value at which to initialize pressure (default=None) temperature : value at which to initialize temperature (default=None) outlvl : sets output level of initialization routine state_vars_fixed: Flag to denote if state vars have already been fixed. - True - states have already been fixed and initialization does not need to worry about fixing and unfixing variables. - False - states have not been fixed. The state block will deal with fixing/unfixing. 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(self.name, outlvl, tag="properties") solve_log = idaeslog.getSolveLogger(self.name, outlvl, tag="properties") if state_vars_fixed is False: # Fix state variables if not already fixed flags = fix_state_vars(self, state_args) else: # Check when the state vars are fixed already result in dof 0 for k in self.keys(): if degrees_of_freedom(self[k]) != 0: raise Exception("State vars fixed but degrees of freedom " "for state block is not zero during " "initialization.") opt = get_solver(solver=solver, options=optarg) with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = solve_indexed_blocks(opt, [self], tee=slc.tee) init_log.info("Initialization Step 1 {}.". format(idaeslog.condition(res))) if state_vars_fixed is False: if hold_state is True: return flags else: self.release_state(flags) init_log.info('Initialization Complete.')
def test_fix_state_vars_None_value(model): model.fs.sb.pressure.value = None with pytest.raises(ConfigurationError): fix_state_vars(model.fs.sb)
def initialize(blk, state_args={}, state_vars_fixed=False, hold_state=False, outlvl=0, solver='ipopt', optarg={'tol': 1e-8}): ''' Initialisation 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 provied at the unit model level, the control volume passes the inlet values as initial guess.The keys for the state_args dictionary are: flow_mol_comp : value at which to initialize component flows (default=None) pressure : value at which to initialize pressure (default=None) temperature : value at which to initialize temperature (default=None) outlvl : sets output level of initialisation routine * 0 = no output (default) * 1 = return solver state for each step in routine * 2 = include solver output infomation (tee=True) state_vars_fixed: Flag to denote if state vars have already been fixed. - True - states have already been fixed by the control volume 1D. Control volume 0D does not fix the state vars, so will be False if this state block is used with 0D blocks. - False - states have not been fixed. The state block will deal with fixing/unfixing. 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. ''' # 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].conc_water_eqn.deactivate() if state_vars_fixed is False: # Fix state variables if not already fixed 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.") opt = SolverFactory(solver) opt.options = optarg # Post initialization reactivate constraints specific for # all blocks other than the inlet for k in blk.keys(): if not blk[k].config.defined_state: blk[k].conc_water_eqn.activate() if state_vars_fixed is False: if hold_state is True: return flags else: blk.release_state(flags) if outlvl > 0: if outlvl > 0: _log.info('{} Initialisation Complete.'.format(blk.name))
def initialize( self, state_args=None, state_vars_fixed=False, hold_state=False, outlvl=idaeslog.NOTSET, solver=None, optarg=None, ): """ 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.The keys for the state_args dictionary are: flow_mass_phase_comp : value at which to initialize phase component flows pressure : value at which to initialize pressure temperature : value at which to initialize temperature outlvl : sets output level of initialization routine (default=idaeslog.NOTSET) optarg : solver options dictionary object (default=None) state_vars_fixed: Flag to denote if state vars have already been fixed. - True - states have already been fixed by the control volume 1D. Control volume 0D does not fix the state vars, so will be False if this state block is used with 0D blocks. - False - states have not been fixed. The state block will deal with fixing/unfixing. solver : Solver object to use during initialization if None is provided it will use the default solver for IDAES (default = None) hold_state : flag indicating whether the initialization routine should unfix any state variables fixed during initialization (default=False). - True - states variables 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 release_state method Returns: If hold_states is True, returns a dict containing flags for which states were fixed during initialization. """ # Get loggers init_log = idaeslog.getInitLogger(self.name, outlvl, tag="properties") solve_log = idaeslog.getSolveLogger(self.name, outlvl, tag="properties") # Set solver and options opt = get_solver(solver, optarg) # Fix state variables flags = fix_state_vars(self, state_args) # Check when the state vars are fixed already result in dof 0 for k in self.keys(): dof = degrees_of_freedom(self[k]) if dof != 0: raise PropertyPackageError( "\nWhile initializing {sb_name}, the degrees of freedom " "are {dof}, when zero is required. \nInitialization assumes " "that the state variables should be fixed and that no other " "variables are fixed. \nIf other properties have a " "predetermined value, use the calculate_state method " "before using initialize to determine the values for " "the state variables and avoid fixing the property variables." "".format(sb_name=self.name, dof=dof)) # --------------------------------------------------------------------- skip_solve = True # skip solve if only state variables are present for k in self.keys(): if number_unfixed_variables(self[k]) != 0: skip_solve = False if not skip_solve: # Initialize properties with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: results = solve_indexed_blocks(opt, [self], tee=slc.tee) init_log.info_high("Property initialization: {}.".format( idaeslog.condition(results))) # --------------------------------------------------------------------- # If input block, return flags, else release state if state_vars_fixed is False: if hold_state is True: return flags else: self.release_state(flags)
def initialize(blk, state_args={}, state_vars_fixed=False, hold_state=False, outlvl=idaeslog.NOTSET, solver=None, optarg={}): ''' 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 provied at the unit model level, the control volume passes the inlet values as initial guess.The keys for the state_args dictionary are: flow_mol_comp : value at which to initialize component flows (default=None) pressure : value at which to initialize pressure (default=None) temperature : value at which to initialize temperature (default=None) outlvl : sets output level of initialization routine state_vars_fixed: Flag to denote if state vars have already been fixed. - True - states have already been fixed and initialization does not need to worry about fixing and unfixing variables. - False - states have not been fixed. The state block will deal with fixing/unfixing. optarg : solver options dictionary object (default={}) solver : str indicating whcih solver to use during initialization (default = None, use default solver) 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") # Deactivate the constraints specific for outlet block i.e. # when defined state is False # This is needed as fixing state vars fixes conc_mol_comp["H2O"], # which is also specified by the conc_water_eqn constraint for k in blk.keys(): if blk[k].config.defined_state is False: blk[k].conc_water_eqn.deactivate() if state_vars_fixed is False: # Fix state variables if not already fixed 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.") if state_vars_fixed is False: if hold_state is True: return flags else: blk.release_state(flags) init_log.info('Initialization Complete.')
def initialize(blk, state_args=None, hold_state=False, state_vars_fixed=False, outlvl=idaeslog.NOTSET, solver=None, optarg=None): """ 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, use default solver options) solver : str indicating which solver to use during initialization (default = None, use default solver) 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.") # Create solver opt = get_solver(solver, optarg) # --------------------------------------------------------------------- # 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: 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)
def initialize(blk, state_args={}, state_vars_fixed=False, hold_state=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 provied at the unit model level, the control volume passes the inlet values as initial guess.The keys for the state_args dictionary are: flow_mol_phase_comp : value at which to initialize phase component flows pressure : value at which to initialize pressure temperature : value at which to initialize temperature outlvl : sets output level of initialization routine * 0 = no output (default) * 1 = return solver state for each step in routine * 2 = include solver output infomation (tee=True) optarg : solver options dictionary object (default=None) state_vars_fixed: Flag to denote if state vars have already been fixed. - True - states have already been fixed by the control volume 1D. Control volume 0D does not fix the state vars, so will be False if this state block is used with 0D blocks. - False - states have not been fixed. The state block will deal with fixing/unfixing. 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") # 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.") # Set solver options if optarg is None: sopt = {"tol": 1e-8} else: sopt = optarg opt = SolverFactory('ipopt') opt.options = sopt # --------------------------------------------------------------------- # If present, initialize bubble and dew point calculations for k in blk.keys(): if hasattr(blk[k], "eq_temperature_dew"): calculate_variable_from_constraint(blk[k].temperature_dew, blk[k].eq_temperature_dew) if hasattr(blk[k], "eq_pressure_dew"): calculate_variable_from_constraint(blk[k].pressure_dew, blk[k].eq_pressure_dew) init_log.info_high("Initialization Step 1 - Dew and bubble points " "calculation completed.") # --------------------------------------------------------------------- # If flash, initialize T1 and Teq for k in blk.keys(): if (blk[k].config.has_phase_equilibrium and not blk[k].config.defined_state): blk[k]._t1.value = max(blk[k].temperature.value, blk[k].temperature_bubble.value) blk[k]._teq.value = min(blk[k]._t1.value, blk[k].temperature_dew.value) init_log.info_high("Initialization Step 2 - Equilibrium temperature " " calculation completed.") # --------------------------------------------------------------------- # Initialize flow rates and compositions # TODO : This will need to be generalised more when we move to a # modular implementation for k in blk.keys(): # Deactivate equilibrium constraints, as state is fixed if hasattr(blk[k], 'equilibrium_constraint'): blk[k].equilibrium_constraint.deactivate() free_vars = 0 for k in blk.keys(): free_vars += number_unfixed_variables(blk[k]) if free_vars > 0: try: with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = solve_indexed_blocks(opt, [blk], tee=slc.tee) except: res = None else: res = None for k in blk.keys(): # Reactivate equilibrium constraints if hasattr(blk[k], 'equilibrium_constraint'): blk[k].equilibrium_constraint.activate() # --------------------------------------------------------------------- # Return state to initial conditions if state_vars_fixed is False: if hold_state is True: return flags else: blk.release_state(flags) init_log.info("Initialization Complete")
def initialize(blk, state_args_feedwater={}, state_args_water_steam={}, outlvl=idaeslog.NOTSET, solver='ipopt', optarg={'tol': 1e-6}): ''' Drum 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 * 0 = no output (default) * 1 = return solver state for each step in routine * 2 = return solver state for each step in subroutines * 3 = include solver output infomation (tee=True) optarg : solver options dictionary object (default={'tol': 1e-6}) solver : str indicating whcih solver to use during initialization (default = 'ipopt') Returns: None ''' init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="unit") solve_log = idaeslog.getSolveLogger(blk.name, outlvl, tag="unit") opt = SolverFactory(solver) opt.options = optarg init_log.info_low("Starting initialization...") # fix FeedWater Inlet flags_fw = fix_state_vars(blk.mixer.FeedWater_state, state_args_feedwater) # expecting 2 DOF due to pressure driven constraint if degrees_of_freedom(blk) != 2: raise Exception(degrees_of_freedom(blk)) blk.flash.initialize(state_args_water_steam=state_args_water_steam, outlvl=outlvl, optarg=optarg, solver=solver) init_log.info("Initialization Step 1 Complete.") blk.mixer.SaturatedWater.flow_mol[:].fix(blk.flash.liq_outlet. flow_mol[0].value) blk.mixer.SaturatedWater.pressure[:].fix(blk.flash.liq_outlet. pressure[0].value) blk.mixer.SaturatedWater.enth_mol[:].fix(blk.flash.liq_outlet. enth_mol[0].value) blk.mixer.initialize(outlvl=outlvl, optarg=optarg, solver=solver) init_log.info("Initialization Step 2 Complete.") blk.control_volume.initialize(outlvl=outlvl, optarg=optarg, solver=solver, hold_state=False) init_log.info("Initialization Step 3 Complete.") # fix flash Inlet flags_steam = fix_state_vars(blk.flash.mixed_state, state_args_water_steam) # unfix inlets (connected with arc) blk.mixer.SaturatedWater.flow_mol[:].unfix() blk.mixer.SaturatedWater.enth_mol[:].unfix() blk.mixer.SaturatedWater.pressure[:].unfix() blk.mixer.FeedWater.pressure[0].unfix() # solve model with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = opt.solve(blk, tee=slc.tee) init_log.info_high( "Initialization Step 4 {}.".format(idaeslog.condition(res)) ) revert_state_vars(blk.mixer.FeedWater_state, flags_fw) revert_state_vars(blk.flash.mixed_state, flags_steam) init_log.info("Initialization Complete.")
def run_case2(xA, xB, xAB=1e-25, scaling=True, rxn_config=None, state="FpcTP"): print("==========================================================================") print( "Case 2 (log form): A and B are aqueous, AB is solid that forms from reaction" ) print("xA = " + str(xA)) print("xB = " + str(xB)) print("xAB = " + str(xAB)) print("scaling = " + str(scaling)) print("including water = " + str(True)) print() model = ConcreteModel() model.fs = FlowsheetBlock(default={"dynamic": False}) if state == "FpcTP": case1_thermo_config["state_definition"] = FpcTP elif state == "FTPx": case1_thermo_config["state_definition"] = FTPx case1_thermo_config["state_bounds"]["flow_mol"] = (0, 50, 100) else: print("Error! Undefined state...") assert False model.fs.thermo_params = GenericParameterBlock(default=case1_thermo_config) model.fs.rxn_params = GenericReactionParameterBlock( default={"property_package": model.fs.thermo_params, **rxn_config} ) model.fs.unit = EquilibriumReactor( default={ "property_package": model.fs.thermo_params, "reaction_package": model.fs.rxn_params, "has_rate_reactions": False, "has_equilibrium_reactions": True, "has_heat_transfer": False, "has_heat_of_reaction": False, "has_pressure_change": False, "energy_balance_type": EnergyBalanceType.none, } ) total_flow_mol = 10 # Set flow_mol_phase_comp if case1_thermo_config["state_definition"] == FpcTP: model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "A"].fix(xA * total_flow_mol) model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "B"].fix(xB * total_flow_mol) model.fs.unit.inlet.flow_mol_phase_comp[0, "Sol", "AB"].fix( xAB * total_flow_mol ) model.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "H2O"].fix( (1 - xA - xB - xAB) * total_flow_mol ) if case1_thermo_config["state_definition"] == FTPx: model.fs.unit.inlet.mole_frac_comp[0, "A"].fix(xA) model.fs.unit.inlet.mole_frac_comp[0, "B"].fix(xB) model.fs.unit.inlet.mole_frac_comp[0, "AB"].fix(xAB) model.fs.unit.inlet.mole_frac_comp[0, "H2O"].fix((1 - xA - xB - xAB)) model.fs.unit.inlet.flow_mol.fix(total_flow_mol) model.fs.unit.inlet.pressure.fix(101325.0) model.fs.unit.inlet.temperature.fix(298.0) model.fs.unit.outlet.temperature.fix(298.0) assert degrees_of_freedom(model) == 0 assert_units_consistent(model) # Scaling _set_eps_vals(model.fs.rxn_params, rxn_config) _set_equ_rxn_scaling(model.fs.unit, rxn_config) if case1_thermo_config["state_definition"] == FpcTP: _set_mat_bal_scaling_FpcTP(model.fs.unit) if case1_thermo_config["state_definition"] == FTPx: _set_mat_bal_scaling_FTPx(model.fs.unit) iscale.calculate_scaling_factors(model.fs.unit) assert isinstance(model.fs.unit.control_volume.scaling_factor, Suffix) # Initialize model if case1_thermo_config["state_definition"] == FpcTP: state_args = { "flow_mol_phase_comp": { ("Liq", "H2O"): model.fs.unit.inlet.flow_mol_phase_comp[ 0, "Liq", "H2O" ].value, ("Liq", "A"): model.fs.unit.inlet.flow_mol_phase_comp[ 0, "Liq", "A" ].value, ("Liq", "B"): model.fs.unit.inlet.flow_mol_phase_comp[ 0, "Liq", "B" ].value, ("Sol", "AB"): model.fs.unit.inlet.flow_mol_phase_comp[ 0, "Sol", "AB" ].value, }, "pressure": 101325, "temperature": 298, "flow_mol": 10, } if case1_thermo_config["state_definition"] == FTPx: state_args = { "mole_frac_comp": { "H2O": model.fs.unit.inlet.mole_frac_comp[0, "H2O"].value, "A": model.fs.unit.inlet.mole_frac_comp[0, "A"].value, "B": model.fs.unit.inlet.mole_frac_comp[0, "B"].value, "AB": model.fs.unit.inlet.mole_frac_comp[0, "AB"].value, }, "pressure": 101325, "temperature": 298, "flow_mol": 10, } flags = fix_state_vars(model.fs.unit.control_volume.properties_out, state_args) revert_state_vars(model.fs.unit.control_volume.properties_out, flags) model.fs.unit.initialize(optarg=solver.options, outlvl=idaeslog.DEBUG) assert degrees_of_freedom(model) == 0 results = solver.solve(model, tee=True) assert results.solver.termination_condition == TerminationCondition.optimal assert results.solver.status == SolverStatus.ok print("comp\toutlet.tot_molfrac") for i in model.fs.unit.control_volume.properties_out[0.0].mole_frac_comp: print( str(i) + "\t" + str( value( model.fs.unit.control_volume.properties_out[0.0].mole_frac_comp[i] ) ) ) print() # NOTE: Changed all to mole fraction for i in model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp: print( str(i) + "\t" + str( value( model.fs.unit.control_volume.properties_out[ 0.0 ].mole_frac_phase_comp[i] ) ) ) A = value( model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp[ "Liq", "A" ] ) B = value( model.fs.unit.control_volume.properties_out[0.0].mole_frac_phase_comp[ "Liq", "B" ] ) Ksp = value(model.fs.unit.control_volume.reactions[0.0].k_eq["AB_Ksp"].expr) print() if Ksp * 1.01 >= A * B: print("Constraint is satisfied!") else: print("Constraint is VIOLATED!") print("\tRelative error: " + str(Ksp / A / B) + ">=1") assert False print("Ksp =\t" + str(Ksp)) print("A*B =\t" + str(A * B)) print("==========================================================================") return model
def initialize( self, state_args={ "flow_mol_comp": { "N2": 1.0, "CO2": 1.0, "NO": 1.0, "O2": 1.0, "H2O": 1.0, "SO2": 1.0 }, "pressure": 1e5, "temperature": 495.0 }, hold_state=False, state_vars_fixed=False, outlvl=0, solver='ipopt', optarg={'tol': 1e-8}): """Initialisation routine for property package. Key values for the state_args dict: flow_mol_comp : value at which to initialize component flows (default=27.5e3 mol/s) pressure : value at which to initialize pressure (default=2.97e7 Pa) temperature : value at which to initialize temperature (default=866.5 K) Args: outlvl: sets logging level state_vars_fixed: Flag to denote state vars have been fixed. - True - states have been fixed by the control volume 1D. Control volume 0D does not fix the state vars, so will be False if this state block is used with 0D blocks. - False - states have not been fixed. The state block will deal with fixing/unfixing. 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(self.name, outlvl, tag="properties") solve_log = idaeslog.getSolveLogger(self.name, outlvl, tag="properties") opt = SolverFactory(solver) opt.options = optarg if state_vars_fixed is False: flags = fix_state_vars(self, state_args) # Check when the state vars are fixed already result in dof 0 for b in self.values(): if degrees_of_freedom(b) != 0: raise Exception(f"{self.name} initializtion error: State vars " "fixed but degrees of freedom not equal to 0") # --------------------------------------------------------------------- # Solve 1st stage for k, b in self.items(): if b.is_property_constructed("pressure_sat"): b.pressure_sat.value = value( exp(b.vapor_pressure_coeff[1] + b.vapor_pressure_coeff[2] / b.temperature + b.vapor_pressure_coeff[3] * blk.temperature + b.vapor_pressure_coeff[4] * log(blk.temperature) + b.vapor_pressure_coeff[5].value * blk.temperature**2)) deactivate_list = [] if hasattr(b, 'enthalpy_correlation'): deactivate_list.append(b.enthalpy_correlation) if hasattr(b, "volumetric_flow_calculation"): deactivate_list.append(b.volumetric_flow_calculation) if hasattr(b, "entropy_correlation"): deactivate_list.append(b.entropy_correlation) for c in deactivate_list: c.deactivate() if number_activated_constraints(b) > 0: with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = opt.solve(b, tee=slc.tee) else: res = "skipped" init_log.info_high("Initialization Step 1 {}.".format( idaeslog.condition(res))) for c in deactivate_list: c.activate() if number_activated_constraints(b) > 0: with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = opt.solve(b, tee=slc.tee) else: res = "skipped" init_log.info_high("Initialization Step 2 {}.".format( idaeslog.condition(res))) init_log.info('Initialisation Complete, {}.'.format( idaeslog.condition(res))) # --------------------------------------------------------------------- # If input block, return flags, else release state if state_vars_fixed is False: if hold_state is True: return flags else: self.release_state(flags)
def initialize(blk, outlvl=idaeslog.NOTSET, optarg={}, solver=None): ''' Initialisation routine for reaction package. Keyword Arguments: outlvl : sets output level of initialization routine optarg : solver options dictionary object (default={}) solver : str indicating whcih solver to use during initialization (default = None, use default solver) Returns: None ''' init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="reactions") solve_log = idaeslog.getSolveLogger(blk.name, outlvl, tag="reactions") init_log.info_high('Starting initialization') # TODO - Update in the future as needed # Get a single representative block for getting config arguments for k in blk.keys(): break # Fix state variables if not already fixed # Fix state variables of the primary (solid) state block state_var_flags = fix_state_vars(blk[k].config.solid_state_block) # Fix values of secondary (gas) state block variables if not fixed, # as well as the solid density variable. # This is done to keep the initialization problem square Cflag = {} # Gas concentration flag Dflag = {} # Solid density flag for k in blk.keys(): for j in blk[k]._params.gas_component_list: if blk[k].gas_state_ref.dens_mol_comp[j].fixed is True: Cflag[k, j] = True else: Cflag[k, j] = False blk[k].gas_state_ref.dens_mol_comp[j].fix( blk[k].gas_state_ref.dens_mol_comp[j].value) if blk[k].solid_state_ref.dens_mass_skeletal.fixed is True: Dflag[k] = True else: Dflag[k] = False blk[k].solid_state_ref.dens_mass_skeletal.fix( blk[k].solid_state_ref.dens_mass_skeletal.value) # Create solver opt = get_solver(solver, optarg) # Initialise values for k in blk.keys(): if hasattr(blk[k], "OC_conv_eqn"): calculate_variable_from_constraint(blk[k].OC_conv, blk[k].OC_conv_eqn) if hasattr(blk[k], "OC_conv_temp_eqn"): calculate_variable_from_constraint(blk[k].OC_conv_temp, blk[k].OC_conv_temp_eqn) for j in blk[k]._params.rate_reaction_idx: if hasattr(blk[k], "rate_constant_eqn"): calculate_variable_from_constraint( blk[k].k_rxn[j], blk[k].rate_constant_eqn[j]) if hasattr(blk[k], "gen_rate_expression"): calculate_variable_from_constraint( blk[k].reaction_rate[j], blk[k].gen_rate_expression[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: 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("reactions initialization complete {}.".format( idaeslog.condition(res))) # --------------------------------------------------------------------- # Revert state vars and other variables to pre-initialization states # Revert state variables of the primary (solid) state block revert_state_vars(blk[k].config.solid_state_block, state_var_flags) for k in blk.keys(): for j in blk[k]._params.gas_component_list: if Cflag[k, j] is False: blk[k].gas_state_ref.dens_mol_comp[j].unfix() if Dflag[k] is False: blk[k].solid_state_ref.dens_mass_skeletal.unfix() init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="reactions") init_log.info_high('States released.')
def initialize(blk, state_args=None, state_vars_fixed=False, hold_state=False, outlvl=idaeslog.NOTSET, solver=None, optarg=None): """ 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_mol, temperature, pressure and mole_frac_comp. outlvl : sets output level of initialization routine optarg : solver options dictionary object (default=None, use default solver options) solver : str indicating which solver to use during initialization (default = None) hold_state : flag indicating whether the initialization routine should unfix any state variables fixed during initialization (default=False). valid options: 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('Starting Vapor phase properties initialization') # Deactivate the constraints specific for non-inlet blocks 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) for k in blk.keys(): dof = degrees_of_freedom(blk[k]) if dof != 0: raise RuntimeError( "{} - degrees of freedom for state block is not zero " "during initialization. DoF = {}".format(blk.name, dof)) # Create solver opt = get_solver(solver, optarg) # --------------------------------------------------------------------- # Initialise values for k in blk.keys(): for j in blk[k].component_list: if hasattr(blk[k], "cp_mol_comp_eqn"): calculate_variable_from_constraint(blk[k].cp_mol_comp[j], blk[k].cp_mol_comp_eqn[j]) if hasattr(blk[k], "flow_mol_comp_eqn"): calculate_variable_from_constraint(blk[k].flow_mol_comp[j], blk[k].flow_mol_comp_eqn[j]) if hasattr(blk[k], "cp_mol_comp_mean_eqn"): calculate_variable_from_constraint(blk[k].cp_mol_comp_mean[j], blk[k].cp_mol_comp_mean_eqn[j]) if hasattr(blk[k], "cp_mol_eqn"): calculate_variable_from_constraint(blk[k].cp_mol, blk[k].cp_mol_eqn) if hasattr(blk[k], "cp_mol_mean_eqn"): calculate_variable_from_constraint(blk[k].cp_mol_mean, blk[k].cp_mol_mean_eqn) if hasattr(blk[k], "enth_mean_eqn"): calculate_variable_from_constraint(blk[k].enth_mean, blk[k].enth_mean_eqn) # Solve property block if non-empty free_vars = 0 for k in blk.keys(): free_vars += number_unfixed_variables(blk[k]) if free_vars > 0: with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: res = solve_indexed_blocks(opt, [blk], tee=slc.tee) else: res = "" init_log.info("Vapor properties initialization complete {}.".format( idaeslog.condition(res))) # ---------------------------------------------------------------------- if state_vars_fixed is False: if hold_state is True: return flags else: blk.release_state(flags)
def calculate_state(self, var_args=None, hold_state=False, outlvl=idaeslog.NOTSET, solver=None, optarg=None): """ Solves state blocks given a set of variables and their values. These variables can be state variables or properties. This method is typically used before initialization to solve for state variables because non-state variables (i.e. properties) cannot be fixed in initialization routines. Keyword Arguments: var_args : dictionary with variables and their values, they can be state variables or properties {(VAR_NAME, INDEX): VALUE} hold_state : flag indicating whether all of the state variables should be fixed after calculate state. True - State variables will be fixed. False - State variables will remain unfixed, unless already fixed. outlvl : idaes logger object that sets output level of solve call (default=idaeslog.NOTSET) solver : solver name string if None is provided the default solver for IDAES will be used (default = None) optarg : solver options dictionary object (default={}) Returns: results object from state block solve """ # Get logger solve_log = idaeslog.getSolveLogger(self.name, level=outlvl, tag="properties") # Initialize at current state values (not user provided) self.initialize(solver=solver, optarg=optarg, outlvl=outlvl) # Set solver and options opt = get_solver(solver, optarg) # Fix variables and check degrees of freedom flags = { } # dictionary noting which variables were fixed and their previous state for k in self.keys(): sb = self[k] for (v_name, ind), val in var_args.items(): var = getattr(sb, v_name) if iscale.get_scaling_factor(var[ind]) is None: _log.warning( "While using the calculate_state method on {sb_name}, variable {v_name} " "was provided as an argument in var_args, but it does not have a scaling " "factor. This suggests that the calculate_scaling_factor method has not been " "used or the variable was created on demand after the scaling factors were " "calculated. It is recommended to touch all relevant variables (i.e. call " "them or set an initial value) before using the calculate_scaling_factor " "method.".format(v_name=v_name, sb_name=sb.name)) if var[ind].is_fixed(): flags[(k, v_name, ind)] = True if value(var[ind]) != val: raise ConfigurationError( "While using the calculate_state method on {sb_name}, {v_name} was " "fixed to a value {val}, but it was already fixed to value {val_2}. " "Unfix the variable before calling the calculate_state " "method or update var_args." "".format(sb_name=sb.name, v_name=var.name, val=val, val_2=value(var[ind]))) else: flags[(k, v_name, ind)] = False var[ind].fix(val) if degrees_of_freedom(sb) != 0: raise RuntimeError( "While using the calculate_state method on {sb_name}, the degrees " "of freedom were {dof}, but 0 is required. Check var_args and ensure " "the correct fixed variables are provided." "".format(sb_name=sb.name, dof=degrees_of_freedom(sb))) # Solve with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: results = solve_indexed_blocks(opt, [self], tee=slc.tee) solve_log.info_high("Calculate state: {}.".format( idaeslog.condition(results))) if not check_optimal_termination(results): _log.warning( "While using the calculate_state method on {sb_name}, the solver failed " "to converge to an optimal solution. This suggests that the user provided " "infeasible inputs, or that the model is poorly scaled, poorly initialized, " "or degenerate.") # unfix all variables fixed with var_args for (k, v_name, ind), previously_fixed in flags.items(): if not previously_fixed: var = getattr(self[k], v_name) var[ind].unfix() # fix state variables if hold_state if hold_state: fix_state_vars(self) return results