def test_get_check_units_on_all_expressions(self): # this method is going to test all the expression types that should work # to be defensive, we will also test that we actually have the expected expression type # therefore, if the expression system changes and we get a different expression type, # we will know we need to change these tests uc = units kg = uc.kg m = uc.m model = ConcreteModel() model.x = Var() model.y = Var() model.z = Var() model.p = Param(initialize=42.0, mutable=True) model.xkg = Var(units=kg) model.ym = Var(units=m) # test equality self._get_check_units_ok(3.0 * kg == 1.0 * kg, uc, 'kg', EXPR.EqualityExpression) self._get_check_units_fail(3.0 * kg == 2.0 * m, uc, EXPR.EqualityExpression) # test inequality self._get_check_units_ok(3.0 * kg <= 1.0 * kg, uc, 'kg', EXPR.InequalityExpression) self._get_check_units_fail(3.0 * kg <= 2.0 * m, uc, EXPR.InequalityExpression) self._get_check_units_ok(3.0 * kg >= 1.0 * kg, uc, 'kg', EXPR.InequalityExpression) self._get_check_units_fail(3.0 * kg >= 2.0 * m, uc, EXPR.InequalityExpression) # test RangedExpression self._get_check_units_ok(inequality(3.0 * kg, 4.0 * kg, 5.0 * kg), uc, 'kg', EXPR.RangedExpression) self._get_check_units_fail(inequality(3.0 * m, 4.0 * kg, 5.0 * kg), uc, EXPR.RangedExpression) self._get_check_units_fail(inequality(3.0 * kg, 4.0 * m, 5.0 * kg), uc, EXPR.RangedExpression) self._get_check_units_fail(inequality(3.0 * kg, 4.0 * kg, 5.0 * m), uc, EXPR.RangedExpression) # test SumExpression, NPV_SumExpression self._get_check_units_ok( 3.0 * model.x * kg + 1.0 * model.y * kg + 3.65 * model.z * kg, uc, 'kg', EXPR.SumExpression) self._get_check_units_fail( 3.0 * model.x * kg + 1.0 * model.y * m + 3.65 * model.z * kg, uc, EXPR.SumExpression) self._get_check_units_ok(3.0 * kg + 1.0 * kg + 2.0 * kg, uc, 'kg', EXPR.NPV_SumExpression) self._get_check_units_fail(3.0 * kg + 1.0 * kg + 2.0 * m, uc, EXPR.NPV_SumExpression) # test ProductExpression, NPV_ProductExpression self._get_check_units_ok(model.x * kg * model.y * m, uc, 'kg*m', EXPR.ProductExpression) self._get_check_units_ok(3.0 * kg * 1.0 * m, uc, 'kg*m', EXPR.NPV_ProductExpression) self._get_check_units_ok(3.0 * kg * m, uc, 'kg*m', EXPR.NPV_ProductExpression) # I don't think that there are combinations that can "fail" for products # test MonomialTermExpression self._get_check_units_ok(model.x * kg, uc, 'kg', EXPR.MonomialTermExpression) # test DivisionExpression, NPV_DivisionExpression self._get_check_units_ok(1.0 / (model.x * kg), uc, '1/kg', EXPR.DivisionExpression) self._get_check_units_ok(2.0 / kg, uc, '1/kg', EXPR.NPV_DivisionExpression) self._get_check_units_ok((model.x * kg) / 1.0, uc, 'kg', EXPR.MonomialTermExpression) self._get_check_units_ok(kg / 2.0, uc, 'kg', EXPR.NPV_DivisionExpression) self._get_check_units_ok(model.y * m / (model.x * kg), uc, 'm/kg', EXPR.DivisionExpression) self._get_check_units_ok(m / kg, uc, 'm/kg', EXPR.NPV_DivisionExpression) # I don't think that there are combinations that can "fail" for products # test PowExpression, NPV_PowExpression # ToDo: fix the str representation to combine the powers or the expression system self._get_check_units_ok( (model.x * kg**2)**3, uc, 'kg**6', EXPR.PowExpression) # would want this to be kg**6 self._get_check_units_fail(kg**model.x, uc, EXPR.PowExpression, UnitsError) self._get_check_units_fail(model.x**kg, uc, EXPR.PowExpression, UnitsError) self._get_check_units_ok(kg**2, uc, 'kg**2', EXPR.NPV_PowExpression) self._get_check_units_fail(3.0**kg, uc, EXPR.NPV_PowExpression, UnitsError) # test NegationExpression, NPV_NegationExpression self._get_check_units_ok(-(kg * model.x * model.y), uc, 'kg', EXPR.NegationExpression) self._get_check_units_ok(-kg, uc, 'kg', EXPR.NPV_NegationExpression) # don't think there are combinations that fan "fail" for negation # test AbsExpression, NPV_AbsExpression self._get_check_units_ok(abs(kg * model.x), uc, 'kg', EXPR.AbsExpression) self._get_check_units_ok(abs(kg), uc, 'kg', EXPR.NPV_AbsExpression) # don't think there are combinations that fan "fail" for abs # test the different UnaryFunctionExpression / NPV_UnaryFunctionExpression types # log self._get_check_units_ok(log(3.0 * model.x), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(log(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(log(3.0 * model.p), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(log(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # log10 self._get_check_units_ok(log10(3.0 * model.x), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(log10(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(log10(3.0 * model.p), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(log10(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # sin self._get_check_units_ok(sin(3.0 * model.x * uc.radians), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(sin(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_fail(sin(3.0 * kg * model.x * uc.kg), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(sin(3.0 * model.p * uc.radians), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(sin(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # cos self._get_check_units_ok(cos(3.0 * model.x * uc.radians), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(cos(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_fail(cos(3.0 * kg * model.x * uc.kg), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(cos(3.0 * model.p * uc.radians), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(cos(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # tan self._get_check_units_ok(tan(3.0 * model.x * uc.radians), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(tan(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_fail(tan(3.0 * kg * model.x * uc.kg), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(tan(3.0 * model.p * uc.radians), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(tan(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # sin self._get_check_units_ok(sinh(3.0 * model.x * uc.radians), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(sinh(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_fail(sinh(3.0 * kg * model.x * uc.kg), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(sinh(3.0 * model.p * uc.radians), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(sinh(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # cos self._get_check_units_ok(cosh(3.0 * model.x * uc.radians), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(cosh(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_fail(cosh(3.0 * kg * model.x * uc.kg), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(cosh(3.0 * model.p * uc.radians), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(cosh(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # tan self._get_check_units_ok(tanh(3.0 * model.x * uc.radians), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(tanh(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_fail(tanh(3.0 * kg * model.x * uc.kg), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(tanh(3.0 * model.p * uc.radians), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(tanh(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # asin self._get_check_units_ok(asin(3.0 * model.x), uc, 'rad', EXPR.UnaryFunctionExpression) self._get_check_units_fail(asin(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(asin(3.0 * model.p), uc, 'rad', EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(asin(3.0 * model.p * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # acos self._get_check_units_ok(acos(3.0 * model.x), uc, 'rad', EXPR.UnaryFunctionExpression) self._get_check_units_fail(acos(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(acos(3.0 * model.p), uc, 'rad', EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(acos(3.0 * model.p * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # atan self._get_check_units_ok(atan(3.0 * model.x), uc, 'rad', EXPR.UnaryFunctionExpression) self._get_check_units_fail(atan(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(atan(3.0 * model.p), uc, 'rad', EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(atan(3.0 * model.p * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # exp self._get_check_units_ok(exp(3.0 * model.x), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_fail(exp(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(exp(3.0 * model.p), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(exp(3.0 * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # sqrt self._get_check_units_ok(sqrt(3.0 * model.x), uc, None, EXPR.UnaryFunctionExpression) self._get_check_units_ok(sqrt(3.0 * model.x * kg**2), uc, 'kg', EXPR.UnaryFunctionExpression) self._get_check_units_ok(sqrt(3.0 * model.x * kg), uc, 'kg**0.5', EXPR.UnaryFunctionExpression) self._get_check_units_ok(sqrt(3.0 * model.p), uc, None, EXPR.NPV_UnaryFunctionExpression) self._get_check_units_ok(sqrt(3.0 * model.p * kg**2), uc, 'kg', EXPR.NPV_UnaryFunctionExpression) self._get_check_units_ok(sqrt(3.0 * model.p * kg), uc, 'kg**0.5', EXPR.NPV_UnaryFunctionExpression) # asinh self._get_check_units_ok(asinh(3.0 * model.x), uc, 'rad', EXPR.UnaryFunctionExpression) self._get_check_units_fail(asinh(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(asinh(3.0 * model.p), uc, 'rad', EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(asinh(3.0 * model.p * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # acosh self._get_check_units_ok(acosh(3.0 * model.x), uc, 'rad', EXPR.UnaryFunctionExpression) self._get_check_units_fail(acosh(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(acosh(3.0 * model.p), uc, 'rad', EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(acosh(3.0 * model.p * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # atanh self._get_check_units_ok(atanh(3.0 * model.x), uc, 'rad', EXPR.UnaryFunctionExpression) self._get_check_units_fail(atanh(3.0 * kg * model.x), uc, EXPR.UnaryFunctionExpression, UnitsError) self._get_check_units_ok(atanh(3.0 * model.p), uc, 'rad', EXPR.NPV_UnaryFunctionExpression) self._get_check_units_fail(atanh(3.0 * model.p * kg), uc, EXPR.NPV_UnaryFunctionExpression, UnitsError) # ceil self._get_check_units_ok(ceil(kg * model.x), uc, 'kg', EXPR.UnaryFunctionExpression) self._get_check_units_ok(ceil(kg), uc, 'kg', EXPR.NPV_UnaryFunctionExpression) # don't think there are combinations that fan "fail" for ceil # floor self._get_check_units_ok(floor(kg * model.x), uc, 'kg', EXPR.UnaryFunctionExpression) self._get_check_units_ok(floor(kg), uc, 'kg', EXPR.NPV_UnaryFunctionExpression) # don't think there are combinations that fan "fail" for floor # test Expr_ifExpression # consistent if, consistent then/else self._get_check_units_ok( EXPR.Expr_if(IF=model.x * kg + kg >= 2.0 * kg, THEN=model.x * kg, ELSE=model.y * kg), uc, 'kg', EXPR.Expr_ifExpression) # unitless if, consistent then/else self._get_check_units_ok( EXPR.Expr_if(IF=model.x >= 2.0, THEN=model.x * kg, ELSE=model.y * kg), uc, 'kg', EXPR.Expr_ifExpression) # consistent if, unitless then/else self._get_check_units_ok( EXPR.Expr_if(IF=model.x * kg + kg >= 2.0 * kg, THEN=model.x, ELSE=model.x), uc, None, EXPR.Expr_ifExpression) # inconsistent then/else self._get_check_units_fail( EXPR.Expr_if(IF=model.x >= 2.0, THEN=model.x * m, ELSE=model.y * kg), uc, EXPR.Expr_ifExpression) # inconsistent then/else NPV self._get_check_units_fail( EXPR.Expr_if(IF=model.x >= 2.0, THEN=model.p * m, ELSE=model.p * kg), uc, EXPR.Expr_ifExpression) # inconsistent then/else NPV units only self._get_check_units_fail( EXPR.Expr_if(IF=model.x >= 2.0, THEN=m, ELSE=kg), uc, EXPR.Expr_ifExpression) # test EXPR.IndexTemplate and GetItemExpression model.S = Set() i = EXPR.IndexTemplate(model.S) j = EXPR.IndexTemplate(model.S) self._get_check_units_ok(i, uc, None, EXPR.IndexTemplate) model.mat = Var(model.S, model.S) self._get_check_units_ok(model.mat[i, j + 1], uc, None, EXPR.GetItemExpression) # test ExternalFunctionExpression, NPV_ExternalFunctionExpression model.ef = ExternalFunction(python_callback_function) self._get_check_units_ok(model.ef(model.x, model.y), uc, None, EXPR.ExternalFunctionExpression) self._get_check_units_ok(model.ef(1.0, 2.0), uc, None, EXPR.NPV_ExternalFunctionExpression) self._get_check_units_fail(model.ef(model.x * kg, model.y), uc, EXPR.ExternalFunctionExpression, UnitsError) self._get_check_units_fail(model.ef(2.0 * kg, 1.0), uc, EXPR.NPV_ExternalFunctionExpression, UnitsError) # test ExternalFunctionExpression, NPV_ExternalFunctionExpression model.ef2 = ExternalFunction(python_callback_function, units=uc.kg) self._get_check_units_ok(model.ef2(model.x, model.y), uc, 'kg', EXPR.ExternalFunctionExpression) self._get_check_units_ok(model.ef2(1.0, 2.0), uc, 'kg', EXPR.NPV_ExternalFunctionExpression) self._get_check_units_fail(model.ef2(model.x * kg, model.y), uc, EXPR.ExternalFunctionExpression, UnitsError) self._get_check_units_fail(model.ef2(2.0 * kg, 1.0), uc, EXPR.NPV_ExternalFunctionExpression, UnitsError) # test ExternalFunctionExpression, NPV_ExternalFunctionExpression model.ef3 = ExternalFunction(python_callback_function, units=uc.kg, arg_units=[uc.kg, uc.m]) self._get_check_units_fail(model.ef3(model.x, model.y), uc, EXPR.ExternalFunctionExpression) self._get_check_units_fail(model.ef3(1.0, 2.0), uc, EXPR.NPV_ExternalFunctionExpression) self._get_check_units_fail(model.ef3(model.x * kg, model.y), uc, EXPR.ExternalFunctionExpression, UnitsError) self._get_check_units_fail(model.ef3(2.0 * kg, 1.0), uc, EXPR.NPV_ExternalFunctionExpression, UnitsError) self._get_check_units_ok(model.ef3(2.0 * kg, 1.0 * uc.m), uc, 'kg', EXPR.NPV_ExternalFunctionExpression) self._get_check_units_ok(model.ef3(model.x * kg, model.y * m), uc, 'kg', EXPR.ExternalFunctionExpression) self._get_check_units_ok(model.ef3(model.xkg, model.ym), uc, 'kg', EXPR.ExternalFunctionExpression) self._get_check_units_fail(model.ef3(model.ym, model.xkg), uc, EXPR.ExternalFunctionExpression, InconsistentUnitsError)
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Sets | +=========================================================================+ | | :code:`PERIODS` | | | *Within*: :code:`PositiveIntegers` | | | | The list of all periods being modeled. Periods must be non-negative | | integers and the set is ordered. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Derived Sets | +=========================================================================+ | | :code:`TMPS_IN_PRD` | | | *Defined over*: :code:`PERIODS` | | | | Indexed set that describes the timepoints that occur in each period. | +-------------------------------------------------------------------------+ | | :code:`NOT_FIRST_PRDS` | | | *Within*: :code:`PERIODS` | | | | The list of periods excluding the first period. Relies on periods being | | ordered. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Required Input Params | +=========================================================================+ | | :code:`discount_factor` | | | *Defined over*: :code:`PERIODS` | | | *Within*: :code:`NonNegativeReals` | | | | Determines the relative objective function weight of investment and | | operational decisions made in each period (i.e. future costs can be | | weighted less). | +-------------------------------------------------------------------------+ | | :code:`number_years_represented` | | | *Defined over*: :code:`PERIODS` | | | *Within*: :code:`NonNegativeReals` | | | | Accounts for the number of years that the periods is meant to | | represent. Investment cost inputs in GridPath are annualized, so they | | are multiplied by this parameter in the objective function. | +-------------------------------------------------------------------------+ | | :code:`hours_in_full_period` | | | *Defined over*: :code:`PERIODS` | | | *Within*: :code:`[8760, 8766, 8784]` | | | | The number of hours in a period. This should be 1 year | | (8760-8784 hours) even if the period represents more than 1 year! | +-------------------------------------------------------------------------+ | | :code:`period` | | | *Defined over*: :code:`TMPS` | | | *Within*: :code:`PERIODS` | | | | Specifies the associated period for each timepoint. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Derived Input Params | +=========================================================================+ | | :code:`first_period` | | | *Within*: :code:`PERIODS` | | | | The first period in the model. Relies on the PERIODS set being ordered. | +-------------------------------------------------------------------------+ | | :code:`prev_period` | | | *Defined over*: :code:`NOT_FIRST_PRDS` | | | *Within*: :code:`PERIODS` | | | | Determines the previous period for each period other than the first | | period, which doesn't have a previous period. | +-------------------------------------------------------------------------+ | | :code:`hours_in_subproblem_period` | | | *Defined over*: :code:`PERIODS` | | | *Within*: :code:`NonNegativeReals` | | | | The number of hours in each period for the current subproblem, taking | | into account the timepoints in each period-subproblem, the number of | | hours in each timepoint, and their associated timepoint weights. | | In capacity expansion mode with one subproblem, this should simply be | | equal to :code:`hours_in_full_period`. In production simulation mode | | with multiple subproblems within 1 period, this number is compared to | | :code: hours_in_full_period` and used to adjust the reported | | "per-period" costs. For instance, when running daily subproblems the | | fixed cost in each day should be only 1/365 of the annualized fixed | | cost. | +-------------------------------------------------------------------------+ """ # Sets ########################################################################### m.PERIODS = Set(within=PositiveIntegers, ordered=True) # Required Input Params ########################################################################### m.discount_factor = Param(m.PERIODS, within=NonNegativeReals) m.number_years_represented = Param(m.PERIODS, within=NonNegativeReals) m.hours_in_full_period = Param(m.PERIODS, within=[8760, 8766, 8784]) # TODO: think numbers_years_represent through and figure out appropriate # documentation wording; can we have periods that are smaller than an # year, considering how costs are defined ($/MW-yr)? m.period = Param(m.TMPS, within=m.PERIODS) # Derived Sets ########################################################################### m.TMPS_IN_PRD = Set(m.PERIODS, initialize=lambda mod, p: list( set(tmp for tmp in mod.TMPS if mod.period[tmp] == p))) m.NOT_FIRST_PRDS = Set(within=m.PERIODS, initialize=lambda mod: list(mod.PERIODS)[1:]) # Derived Input Params ########################################################################### m.first_period = Param(within=m.PERIODS, initialize=lambda mod: list(mod.PERIODS)[0]) m.prev_period = Param(m.NOT_FIRST_PRDS, within=m.PERIODS, initialize=lambda mod, p: list(mod.PERIODS)[list( mod.PERIODS).index(p) - 1]) m.hours_in_subproblem_period = Param( m.PERIODS, within=NonNegativeReals, initialize=lambda mod, p: sum(mod.hrs_in_tmp[tmp] * mod.tmp_weight[tmp] for tmp in mod.TMPS_IN_PRD[p]))
def build(self): ''' Callable method for Block construction. ''' super(ReactionParameterBlock, self).build() self._reaction_block_class = ReactionBlock # Create Phase objects self.Vap = VaporPhase() self.Sol = SolidPhase() # Create Component objects self.CH4 = Component() self.CO2 = Component() self.H2O = Component() self.Fe2O3 = Component() self.Fe3O4 = Component() self.Al2O3 = Component() # Component list subsets self.gas_component_list = Set(initialize=['CO2', 'H2O', 'CH4']) self.sol_component_list = Set(initialize=['Fe2O3', 'Fe3O4', 'Al2O3']) # Reaction Index self.rate_reaction_idx = Set(initialize=["R1"]) # Gas Constant self.gas_const = Param(within=PositiveReals, mutable=False, default=8.314459848e-3, doc='Gas Constant [kJ/mol.K]') # Smoothing factor self.eps = Param(mutable=True, default=1e-8, doc='Smoothing Factor') # Reaction rate scale factor self._scale_factor_rxn = Param(mutable=True, default=1, doc='Scale Factor for reaction eqn.' 'Used to help initialization routine') # Reaction Stoichiometry self.rate_reaction_stoichiometry = { ("R1", "Vap", "CH4"): -1, ("R1", "Vap", "CO2"): 1, ("R1", "Vap", "H2O"): 2, ("R1", "Sol", "Fe2O3"): -12, ("R1", "Sol", "Fe3O4"): 8, ("R1", "Sol", "Al2O3"): 0 } # Reaction stoichiometric coefficient self.rxn_stoich_coeff = Param(self.rate_reaction_idx, default=12, mutable=True, doc='Reaction stoichiometric' 'coefficient [-]') # Standard Heat of Reaction - kJ/mol_rxn dh_rxn_dict = {"R1": 136.5843} self.dh_rxn = Param(self.rate_reaction_idx, initialize=dh_rxn_dict, doc="Heat of reaction [kJ/mol]") # ------------------------------------------------------------------------- """ Reaction properties that can be estimated""" # Particle grain radius within OC particle self.grain_radius = Var(domain=Reals, initialize=2.6e-7, doc='Representative particle grain' 'radius within OC particle [m]') self.grain_radius.fix() # Molar density OC particle self.dens_mol_sol = Var(domain=Reals, initialize=32811, doc='Molar density of OC particle [mol/m^3]') self.dens_mol_sol.fix() # Available volume for reaction - from EPAT report (1-ep)' self.a_vol = Var(domain=Reals, initialize=0.28, doc='Available reaction vol. per vol. of OC') self.a_vol.fix() # Activation Energy self.energy_activation = Var(self.rate_reaction_idx, domain=Reals, initialize=4.9e1, doc='Activation energy [kJ/mol]') self.energy_activation.fix() # Reaction order self.rxn_order = Var(self.rate_reaction_idx, domain=Reals, initialize=1.3, doc='Reaction order in gas species [-]') self.rxn_order.fix() # Pre-exponential factor self.k0_rxn = Var(self.rate_reaction_idx, domain=Reals, initialize=8e-4, doc='Pre-exponential factor' '[mol^(1-N_reaction)m^(3*N_reaction -2)/s]') self.k0_rxn.fix()
def build(self): ''' Callable method for Block construction. ''' super(PhysicalParameterData, self).build() self.state_block_class = MethaneCombustionStateBlock # List of valid phases in property package self.phase_list = Set(initialize=['Vap']) # Component list - a list of component identifiers self.component_list = Set( initialize=['H2', 'N2', 'O2', 'CH4', 'CO', 'CO2', 'H2O', 'NH3']) # List of components in each phase (optional) self.phase_comp = {"Vap": self.component_list} # List of all chemical elements that constitute the chemical species self.element_list = Set(initialize=['H', 'N', 'O', 'C']) # Elemental composition of all species self.element_comp = { 'H2': { 'H': 2, 'N': 0, 'O': 0, 'C': 0 }, 'N2': { 'H': 0, 'N': 2, 'O': 0, 'C': 0 }, 'O2': { 'H': 0, 'N': 0, 'O': 2, 'C': 0 }, 'CH4': { 'H': 4, 'N': 0, 'O': 0, 'C': 1 }, 'CO': { 'H': 0, 'N': 0, 'O': 1, 'C': 1 }, 'CO2': { 'H': 0, 'N': 0, 'O': 2, 'C': 1 }, 'H2O': { 'H': 2, 'N': 0, 'O': 1, 'C': 0 }, 'NH3': { 'H': 3, 'N': 1, 'O': 0, 'C': 0 } } # Heat capacity parameters - Shomate eqn (from NIST webbook) # Parameter 9 is the enthalpy at 1500K (Tref) in J/mol cp_param_dict = { ('H2', 1): 18.563083, ('H2', 2): 12.257357, ('H2', 3): -2.859786, ('H2', 4): 0.268238, ('H2', 5): 1.977990, ('H2', 6): -1.147438, ('H2', 7): 156.288133, ('H2', 8): 0.0, ('H2', 9): 36290.28, ('N2', 1): 19.50583, ('N2', 2): 19.88705, ('N2', 3): -8.598535, ('N2', 4): 1.369784, ('N2', 5): 0.527601, ('N2', 6): -4.935202, ('N2', 7): 212.3900, ('N2', 8): 0, ('N2', 9): 38405.02, ('O2', 1): 30.03235, ('O2', 2): 8.772972, ('O2', 3): -3.988133, ('O2', 4): 0.788313, ('O2', 5): -0.741599, ('O2', 6): -11.32468, ('O2', 7): 236.1663, ('O2', 8): 0, ('O2', 9): 40598.9, ('CH4', 1): 85.81217, ('CH4', 2): 11.26467, ('CH4', 3): -2.114146, ('CH4', 4): 0.138190, ('CH4', 5): -26.42221, ('CH4', 6): -153.5327, ('CH4', 7): 224.4143, ('CH4', 8): -74.87310, ('CH4', 9): 78142.7, ('CO', 1): 35.15070, ('CO', 2): 1.300095, ('CO', 3): -0.205921, ('CO', 4): 0.013550, ('CO', 5): -3.282780, ('CO', 6): -127.8375, ('CO', 7): 231.7120, ('CO', 8): -110.5271, ('CO', 9): 38852.26, ('CO2', 1): 58.16639, ('CO2', 2): 2.720074, ('CO2', 3): -0.492289, ('CO2', 4): 0.038844, ('CO2', 5): -6.447293, ('CO2', 6): -425.9186, ('CO2', 7): 263.6125, ('CO2', 8): -393.5224, ('CO2', 9): 61707.0, ('H2O', 1): 41.96426, ('H2O', 2): 8.622053, ('H2O', 3): -1.499780, ('H2O', 4): 0.098119, ('H2O', 5): -11.15764, ('H2O', 6): -272.1797, ('H2O', 7): 219.7809, ('H2O', 8): -241.8264, ('H2O', 9): 48150.13, ('NH3', 1): 52.02427, ('NH3', 2): 18.48801, ('NH3', 3): -3.765128, ('NH3', 4): 0.248541, ('NH3', 5): -12.45799, ('NH3', 6): -85.53895, ('NH3', 7): 223.8022, ('NH3', 8): -45.89806, ('NH3', 9): 63578.64 } self.cp_params = Param(self.component_list, range(1, 10), mutable=False, initialize=cp_param_dict, doc="Shomate equation heat capacity parameters") # Heat of Formation hf_dict = { "CH4": -74600, "CO": -110530, "CO2": -393520, "H2": 0, "H2O": -241830, "N2": 0, "NH3": -45900, "O2": 0 } self.enth_mol_form = Param( self.component_list, mutable=False, initialize=hf_dict, doc="Component molar heats of formation [J/mol]") # Gas Constant self.gas_const = Param(within=PositiveReals, mutable=False, default=8.314, doc='Gas Constant [J/mol.K]') # Thermodynamic reference state self.pressure_ref = Param(within=PositiveReals, mutable=True, default=101325.0, doc='Reference pressure [Pa]') self.temperature_ref = Param(within=PositiveReals, mutable=True, default=1500.0, doc='Reference temperature [K]')
def _visc_d(self): self.visc_d = Param(initialize=self.params.visc_d_default, units=pyunits.kg / pyunits.m / pyunits.s, mutable=True, doc="Dynamic viscosity of solution")
def build(self): super(Iapws95ParameterBlockData, self).build() self.state_block_class = Iapws95StateBlock # Location of the *.so or *.dll file for external functions self.plib = os.path.dirname(__file__) self.plib = os.path.join(self.plib, "iapws95.so") self.available = os.path.isfile(self.plib) # Phase list self.private_phase_list = Set(initialize=["Vap", "Liq"]) self.phase_list = Set(initialize=["Mix"]) # Component list - a list of component identifiers self.component_list = Set(initialize=['H2O']) # Parameters, these should match what's in the C code self.temperature_crit = Param(initialize=647.096, doc='Critical temperature [K]') self.pressure_crit = Param(initialize=2.2064e7, doc='Critical pressure [Pa]') self.dens_mass_crit = Param(initialize=322, doc='Critical density [kg/m3]') self.gas_const = Param(initialize=8.3144598, doc='Gas Constant [J/mol/K]') self.mw = Param(initialize=0.01801528, doc='Molecular weight [kg/mol]') #Thermal conductivity parameters. # "Release on the IAPWS Formulation 2011 for the Thermal Conductivity of # Ordinary Water Substance" self.tc_L0 = Param(RangeSet(0, 5), initialize={ 0: 2.443221e-3, 1: 1.323095e-2, 2: 6.770357e-3, 3: -3.454586e-3, 4: 4.096266e-4 }, doc="0th order themalcondutivity paramters") self.tc_L1 = Param(RangeSet(0, 5), RangeSet(0, 6), initialize={ (0, 0): 1.60397357, (1, 0): 2.33771842, (2, 0): 2.19650529, (3, 0): -1.21051378, (4, 0): -2.7203370, (0, 1): -0.646013523, (1, 1): -2.78843778, (2, 1): -4.54580785, (3, 1): 1.60812989, (4, 1): 4.57586331, (0, 2): 0.111443906, (1, 2): 1.53616167, (2, 2): 3.55777244, (3, 2): -0.621178141, (4, 2): -3.18369245, (0, 3): 0.102997357, (1, 3): -0.463045512, (2, 3): -1.40944978, (3, 3): 0.0716373224, (4, 3): 1.1168348, (0, 4): -0.0504123634, (1, 4): 0.0832827019, (2, 4): 0.275418278, (3, 4): 0.0, (4, 4): -0.19268305, (0, 5): 0.00609859258, (1, 5): -0.00719201245, (2, 5): -0.0205938816, (3, 5): 0.0, (4, 5): 0.012913842 }, doc="1st order themalcondutivity paramters") #Viscosity paramters #"Release on the IAPWS Formulation 2008 for the Viscosity of # Ordinary Water Substance " self.visc_H0 = Param(RangeSet(0, 4), initialize={ 0: 1.67752, 1: 2.20462, 2: 0.6366564, 3: -0.241605 }, doc="0th order viscosity parameters") self.visc_H1 = Param(RangeSet(0, 6), RangeSet(0, 7), initialize={ (0, 0): 5.20094e-1, (1, 0): 8.50895e-2, (2, 0): -1.08374, (3, 0): -2.89555e-1, (4, 0): 0.0, (5, 0): 0.0, (0, 1): 2.22531e-1, (1, 1): 9.99115e-1, (2, 1): 1.88797, (3, 1): 1.26613, (4, 1): 0.0, (5, 1): 1.20573e-1, (0, 2): -2.81378e-1, (1, 2): -9.06851e-1, (2, 2): -7.72479e-1, (3, 2): -4.89837e-1, (4, 2): -2.57040e-1, (5, 2): 0.0, (0, 3): 1.61913e-1, (1, 3): 2.57399e-1, (2, 3): 0.0, (3, 3): 0.0, (4, 3): 0.0, (5, 3): 0.0, (0, 4): -3.25372e-2, (1, 4): 0.0, (2, 4): 0.0, (3, 4): 6.98452e-2, (4, 4): 0.0, (5, 4): 0.0, (0, 5): 0.0, (1, 5): 0.0, (2, 5): 0.0, (3, 5): 0.0, (4, 5): 8.72102e-3, (5, 5): 0.0, (0, 6): 0.0, (1, 6): 0.0, (2, 6): 0.0, (3, 6): -4.35673e-3, (4, 6): 0.0, (5, 6): -5.93264e-4 }, doc="1st order viscosity parameters")
def build(self): self._set_parameters( library=_so, eos_tag="swco2", state_block_class=SWCO2StateBlock, component_list=Set(initialize=["CO2"]), phase_equilibrium_idx=Set(initialize=[1]), phase_equilibrium_list={1: ["CO2", ("Vap", "Liq")]}, mw=Param(initialize=0.0440098, doc="Molecular weight [kg/mol]", units=pyunits.kg / pyunits.mol), temperature_crit=Param(initialize=304.1282, doc="Critical temperature [K]", units=pyunits.K), pressure_crit=Param(initialize=7.377e6, doc="Critical pressure [Pa]", units=pyunits.Pa), dens_mass_crit=Param(initialize=467.6, doc="Critical density [kg/m3]", units=pyunits.kg / pyunits.m**3), specific_gas_constant=Param( initialize=188.9241, doc="CO2 Specific Gas Constant [J/kg/K]", units=pyunits.J / pyunits.kg / pyunits.K), pressure_bounds=(0.1, 1e9), temperature_bounds=(210, 2500), enthalpy_bounds=(-2e4, 1e5), ) super().build() # Thermal conductivity parameters. # Vesovic et al. (1990) self.tc_b = Param( RangeSet(0, 8), initialize={ 0: 0.4226159, 1: 0.6280115, 2: -0.5387661, 3: 0.6735941, 4: 0, 5: 0, 6: -0.4362677, 7: 0.2255388, }, doc="0 density limit thermal conductivity parameters", ) self.tc_c = Param( RangeSet(1, 6), initialize={ 1: 2.387869e-2, 2: 4.350794, 3: -10.33404, 4: 7.981590, 5: -1.940558, }, doc="0 density limit thermal conductivity parameters", ) self.tc_d_1 = Param(initialize=2.447164e-5 * self.dens_mass_crit, doc="Residual thermal conductivity parameter", units=pyunits.W / pyunits.K / pyunits.m) self.tc_d_2 = Param(initialize=8.705605e-8 * self.dens_mass_crit**2, doc="Residual thermal conductivity parameter", units=pyunits.W / pyunits.K / pyunits.m) self.tc_d_3 = Param(initialize=-6.547950e-11 * self.dens_mass_crit**3, doc="Residual thermal conductivity parameter", units=pyunits.W / pyunits.K / pyunits.m) self.tc_d_4 = Param(initialize=6.594919e-14 * self.dens_mass_crit**4, doc="Residual thermal conductivity parameter", units=pyunits.W / pyunits.K / pyunits.m) # Viscosity parameters # "Fenghour et al. (1998) with critial enhancment Vesovic et al. (1990) self.visc_a = Param( RangeSet(0, 5), initialize={ 0: 0.235156, 1: -0.491266, 2: 5.211155e-2, 3: 5.347906e-2, 4: -1.537102e-2, }, doc="0 density limit viscosity parameters", ) # The indexing looks a little weird here, but it's from the source self.visc_d_1_1 = Param(initialize=0.4071119e-8 * self.dens_mass_crit, doc="Residual viscosity parameter", units=pyunits.Pa * pyunits.s) self.visc_d_2_1 = Param(initialize=0.7198037e-10 * self.dens_mass_crit**2, doc="Residual viscosity parameter", units=pyunits.Pa * pyunits.s) self.visc_d_6_4 = Param(initialize=0.2411697e-22 * self.dens_mass_crit**6, doc="Residual viscosity parameter", units=pyunits.Pa * pyunits.s) self.visc_d_8_1 = Param(initialize=0.2971072e-28 * self.dens_mass_crit**8, doc="Residual viscosity parameter", units=pyunits.Pa * pyunits.s) self.visc_d_8_2 = Param(initialize=-0.1627888e-28 * self.dens_mass_crit**8, doc="Residual viscosity parameter", units=pyunits.Pa * pyunits.s) self.set_default_scaling("therm_cond_phase", 1e2, index="Liq") self.set_default_scaling("therm_cond_phase", 1e1, index="Vap") self.set_default_scaling("visc_d_phase", 1e5, index="Liq") self.set_default_scaling("visc_d_phase", 1e6, index="Vap") self.set_default_scaling("visc_k_phase", 1e5, index="Liq") self.set_default_scaling("visc_k_phase", 1e7, index="Vap")
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Sets | +=========================================================================+ | | :code:`DR_NEW` | | | | The list of :code:`dr_new` projects being modeled. | +-------------------------------------------------------------------------+ | | :code:`DR_NEW_OPR_PRDS` | | | | Two-dimensional set of all :code:`dr_new` projects and their | | operational periods. | +-------------------------------------------------------------------------+ | | :code:`DR_NEW_PTS` | | | | Two-dimensional set of all :code:`dr_new` projects and their supply | | curve points. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Required Input Params | +=========================================================================+ | | :code:`dr_new_min_duration` | | | *Defined over*: :code:`DR_NEW` | | | *Within*: :code:`NonNegativeReals` | | | | The project's duration in hours, i.e. how many hours the load can be | | shifted. | +-------------------------------------------------------------------------+ | | :code:`dr_new_min_cumulative_new_build_mwh` | | | *Defined over*: :code:`DR_NEW_OPR_PRDS` | | | *Within*: :code:`NonNegativeReals` | | | | The minimum cumulative amount of shiftable load capacity (in MWh) that | | must be built for a project by a certain period. | +-------------------------------------------------------------------------+ | | :code:`dr_new_max_cumulative_new_build_mwh` | | | *Defined over*: :code:`DR_NEW_OPR_PRDS` | | | *Within*: :code:`NonNegativeReals` | | | | The maximum cumulative amount of shiftable load capacity (in MWh) that | | must be built for a project by a certain period. | +-------------------------------------------------------------------------+ | | :code:`dr_new_supply_curve_slope` | | | *Defined over*: :code:`DR_NEW_PTS` | | | *Within*: :code:`NonNegativeReals` | | | | The project's slope for each point (section) in the piecewise linear | | supply cost curve, in $ per MWh. | +-------------------------------------------------------------------------+ | | :code:`dr_new_supply_curve_intercept` | | | *Defined over*: :code:`DR_NEW_PTS` | | | *Within*: :code:`NonNegativeReals` | | | | The project's intercept for each point (section) in the piecewise | | linear supply cost curve, in $. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Variables | +=========================================================================+ | | :code:`DRNew_Build_MWh` | | | *Defined over*: :code:`DR_NEW_OPR_PRDS` | | | *Within*: :code:`NonNegativeReals` | | | | Determines how much shiftable load capacity (in MWh) is built in each | | operational period. | +-------------------------------------------------------------------------+ | | :code:`DRNew_Cost` | | | *Defined over*: :code:`DR_NEW_OPR_PRDS` | | | *Within*: :code:`NonNegativeReals` | | | | The cost of new shiftable load capacity in each operational period. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Expressions | +=========================================================================+ | | :code:`DRNew_Energy_Capacity_MWh` | | | *Defined over*: :code:`DR_NEW_OPR_PRDS` | | | *Within*: :code:`NonNegativeReals` | | | | The project's total energy capacity (in MWh) in each operational period | | is the sum of the new-built energy capacity in all of the previous | | periods. | +-------------------------------------------------------------------------+ | | :code:`DRNew_Power_Capacity_MW` | | | *Defined over*: :code:`DR_NEW_OPR_PRDS` | | | *Within*: :code:`NonNegativeReals` | | | | The project's total power capacity (in MW) in each operational period | | is equal to the total energy capacity in that period, divided by the | | project's minimum duraiton (in hours). | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Constraints | +=========================================================================+ | | :code:`DRNew_Cost_Constraint` | | | *Defined over*: :code:`DR_NEW_PTS*PERIODS` | | | | Ensures that the project's cost in each operational period is larger | | than the calculated piecewise linear cost in each segment. Only one | | segment will bind at a time. | +-------------------------------------------------------------------------+ """ # Sets ########################################################################### m.DR_NEW = Set() m.DR_NEW_OPR_PRDS = Set(dimen=2, initialize=m.DR_NEW * m.PERIODS) m.DR_NEW_PTS = Set(dimen=2, within=m.DR_NEW * list(range(1, 1001))) # Required Params ########################################################################### m.dr_new_min_duration = Param(m.DR_NEW, within=NonNegativeReals) m.dr_new_min_cumulative_new_build_mwh = Param( m.DR_NEW, m.PERIODS, within=NonNegativeReals # TODO: change to DR_NEW_OPR_PRDS? ) m.dr_new_max_cumulative_new_build_mwh = Param( m.DR_NEW, m.PERIODS, within=NonNegativeReals # TODO: change to DR_NEW_OPR_PRDS? ) m.dr_new_supply_curve_slope = Param(m.DR_NEW_PTS, within=NonNegativeReals) m.dr_new_supply_curve_intercept = Param(m.DR_NEW_PTS, within=Reals) # Variables ########################################################################### m.DRNew_Build_MWh = Var( m.DR_NEW, m.PERIODS, within=NonNegativeReals # TODO: change to DR_NEW_OPR_PRDS? ) m.DRNew_Cost = Var(m.DR_NEW_OPR_PRDS, within=NonNegativeReals) # Expressions ########################################################################### m.DRNew_Energy_Capacity_MWh = Expression( m.DR_NEW_OPR_PRDS, rule=dr_new_energy_capacity_rule ) m.DRNew_Power_Capacity_MW = Expression( m.DR_NEW_OPR_PRDS, rule=dr_new_power_capacity_rule ) # Constraints ########################################################################### m.DRNew_Cost_Constraint = Constraint( m.DR_NEW_PTS * m.PERIODS, rule=cost_rule # TODO: define new set? ) # Dynamic Components ########################################################################### # Add to list of sets we'll join to get the final # PRJ_OPR_PRDS set getattr(d, capacity_type_operational_period_sets).append( "DR_NEW_OPR_PRDS", )
def _pressure_bubble(self): self.pressure_bubble = Param(initialize=1e8, doc="Bubble point pressure (Pa)")
def Model_Creation_Dispatch(model): ''' This function creates the instance for the resolution of the optimization in Pyomo. The problem is solved by discretizing the efficiency curve of the generators and uses binary variables :param model: Pyomo model as defined in the Micro-Grids library. ''' from pyomo.environ import Param, RangeSet, NonNegativeReals, Var, NonNegativeIntegers from Initialize import Initialize_Demand, Initialize_PV_Energy, Initialize_Demand_Dispatch, Initialize_PV_Energy_Dispatch, Marginal_Cost_Generator, Start_Cost,Marginal_Cost_Generator_1,Max_Power_Battery_Discharge, Max_Power_Battery_Charge # Import library with initialitation funtions for the parameters # Time parameters model.Periods = Param(within=NonNegativeReals) # Number of periods of analysis of the energy variables model.StartDate = Param() # Start date of the analisis model.PlotTime = Param() # Quantity of days that are going to be plot model.PlotDay = Param() # Start day for the plot #SETS model.periods = RangeSet(1, model.Periods) # Creation of a set from 1 to the number of periods in each year # PARAMETERS # Parameters of the PV model.Total_Energy_PV = Param(model.periods, within=NonNegativeReals, initialize=Initialize_PV_Energy_Dispatch) # Energy produccion of a solar panel in W # Parameters of the battery bank model.Charge_Battery_Efficiency = Param() # Efficiency of the charge of the battery in % model.Discharge_Battery_Efficiency = Param() # Efficiency of the discharge of the battery in % model.Deep_of_Discharge = Param() # Deep of discharge of the battery (Deep_of_Discharge) in % model.Maximun_Battery_Charge_Time = Param(within=NonNegativeReals) # Minimun time of charge of the battery in hours model.Maximun_Battery_Discharge_Time = Param(within=NonNegativeReals) # Maximun time of discharge of the battery in hours model.Battery_Nominal_Capacity = Param(within=NonNegativeReals) # Capacity of the battery bank in Wh model.Maximun_Charge_Power= Param(initialize=Max_Power_Battery_Charge) # Maximun charge power in w model.Maximun_Discharge_Power = Param(initialize=Max_Power_Battery_Discharge) #Maximun discharge power in w model.Battery_Initial_SOC = Param(within=NonNegativeReals) # Parametes of the diesel generator model.Generator_Effiency = Param(within=NonNegativeReals) model.Generator_Min_Out_Put = Param(within=NonNegativeReals) model.Low_Heating_Value = Param() # Low heating value of the diesel in W/L model.Diesel_Cost = Param(within=NonNegativeReals) # Cost of diesel in USD/L model.Marginal_Cost_Generator_1 = Param(initialize=Marginal_Cost_Generator_1) model.Cost_Increase = Param(within=NonNegativeReals) model.Generator_Nominal_Capacity = Param(within=NonNegativeReals) model.Start_Cost_Generator = Param(within=NonNegativeReals, initialize=Start_Cost) model.Marginal_Cost_Generator = Param(initialize=Marginal_Cost_Generator) # Parameters of the Energy balance model.Energy_Demand = Param(model.periods, initialize=Initialize_Demand_Dispatch) # Energy Energy_Demand in W model.Lost_Load_Probability = Param() # Lost load probability in % model.Value_Of_Lost_Load = Param(within=NonNegativeReals) # Value of lost load in USD/W # Parameters of the proyect model.Delta_Time = Param(within=NonNegativeReals) # Time step in hours # VARIABLES # Variables associated to the battery bank model.Energy_Battery_Flow_Out = Var(model.periods, within=NonNegativeReals) # Battery discharge energy in wh model.Energy_Battery_Flow_In = Var(model.periods, within=NonNegativeReals) # Battery charge energy in wh model.State_Of_Charge_Battery = Var(model.periods, within=NonNegativeReals) # State of Charge of the Battery in wh # Variables associated to the diesel generator model.Period_Total_Cost_Generator = Var(model.periods, within=NonNegativeReals) model.Energy_Generator_Total = Var(model.periods, within=NonNegativeReals) model.Integer_generator = Var(within=NonNegativeIntegers) model.Total_Cost_Generator = Var(within=NonNegativeReals) model.Generator_Total_Period_Energy = Var(model.periods, within=NonNegativeReals) model.Generator_Energy_Integer = Var(model.periods, within=NonNegativeIntegers) model.Last_Energy_Generator = Var(model.periods, within=NonNegativeReals) # Varialbles associated to the energy balance model.Lost_Load = Var(model.periods, within=NonNegativeReals) # Energy not suply by the system kWh model.Energy_Curtailment = Var(model.periods, within=NonNegativeReals) # Curtailment of solar energy in kWh # Variables associated to the project model.Scenario_Lost_Load_Cost = Var(within=NonNegativeReals) ####
def Model_Creation(model): ''' This function creates the instance for the resolution of the optimization in Pyomo. :param model: Pyomo model as defined in the Micro-Grids library. ''' # Time parameters model.Periods = Param(within=NonNegativeReals) # Number of periods of analysis of the energy variables model.Years = Param() # Number of years of the project model.StartDate = Param() # Start date of the analisis model.PlotTime = Param() # Quantity of days that are going to be plot model.PlotDay = Param() # Start day for the plot model.PlotScenario = Param() model.Scenarios = Param() #SETS model.periods = RangeSet(1, model.Periods) # Creation of a set from 1 to the number of periods in each year model.years = RangeSet(1, model.Years) # Creation of a set from 1 to the number of years of the project model.scenario = RangeSet(1, model.Scenarios) # Creation of a set from 1 to the numbero scenarios to analized # PARAMETERS # Parameters of the PV model.PV_Nominal_Capacity = Param(within=NonNegativeReals) # Nominal capacity of the PV in W/unit model.Inverter_Efficiency = Param() # Efficiency of the inverter in % model.PV_invesment_Cost = Param(within=NonNegativeReals) # Cost of solar panel in USD/W model.PV_Energy_Production = Param(model.scenario, model.periods, within=NonNegativeReals, initialize=Initialize_PV_Energy) # Energy produccion of a solar panel in W # Parameters of the battery bank model.Charge_Battery_Efficiency = Param() # Efficiency of the charge of the battery in % model.Discharge_Battery_Efficiency = Param() # Efficiency of the discharge of the battery in % model.Deep_of_Discharge = Param() # Deep of discharge of the battery (Deep_of_Discharge) in % model.Maximun_Battery_Charge_Time = Param(within=NonNegativeReals) # Minimun time of charge of the battery in hours model.Maximun_Battery_Discharge_Time = Param(within=NonNegativeReals) # Maximun time of discharge of the battery in hours model.Battery_Reposition_Time = Param(within=NonNegativeReals) # Period of repocition of the battery in years model.Battery_Invesment_Cost = Param() # Cost of battery # Parametes of the diesel generator model.Generator_Efficiency = Param() # Generator efficiency to trasform heat into electricity % model.Low_Heating_Value = Param() # Low heating value of the diesel in W/L model.Diesel_Unitary_Cost = Param(within=NonNegativeReals) # Cost of diesel in USD/L model.Generator_Invesment_Cost = Param(within=NonNegativeReals) # Cost of the diesel generator # Parameters of the Energy balance model.Energy_Demand = Param(model.scenario, model.periods, initialize=Initialize_Demand) # Energy Energy_Demand in W model.Lost_Load_Probability = Param(within=NonNegativeReals) # Lost load probability in % model.Value_Of_Lost_Load = Param(within=NonNegativeReals) # Value of lost load in USD/W # Parameters of the proyect model.Delta_Time = Param(within=NonNegativeReals) # Time step in hours model.Porcentage_Funded = Param(within=NonNegativeReals) # Porcentaje of the total investment that is Porcentage_Porcentage_Funded by a bank or another entity in % model.Project_Years = Param(model.years, initialize= Initialize_years) # Years of the project model.Maintenance_Operation_Cost_PV = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in % model.Maintenance_Operation_Cost_Battery = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in % model.Maintenance_Operation_Cost_Generator = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in % model.Discount_Rate = Param() # Discount rate of the project in % model.Interest_Rate_Loan = Param() # Interest rate of the loan in % model.Scenario_Weight = Param(model.scenario, within=NonNegativeReals) ######### # VARIABLES # Variables associated to the solar panels model.PV_Units = Var(within=NonNegativeReals) # Number of units of solar panels model.Total_Energy_PV = Var(model.scenario,model.periods, within=NonNegativeReals) # Energy generated for the Pv sistem in Wh # Variables associated to the battery bank model.Battery_Nominal_Capacity = Var(within=NonNegativeReals) # Capacity of the battery bank in Wh model.Energy_Battery_Flow_Out = Var(model.scenario, model.periods, within=NonNegativeReals) # Battery discharge energy in wh model.Energy_Battery_Flow_In = Var(model.scenario, model.periods, within=NonNegativeReals) # Battery charge energy in wh model.State_Of_Charge_Battery = Var(model.scenario, model.periods, within=NonNegativeReals) # State of Charge of the Battery in wh # Variables associated to the diesel generator model.Generator_Nominal_Capacity = Var(within=NonNegativeReals) # Capacity of the diesel generator in Wh model.Diesel_Consume = Var(model.scenario,model.periods, within=NonNegativeReals) # Diesel consumed to produce electric energy in L model.Generator_Energy = Var(model.scenario, model.periods, within=NonNegativeReals) # Energy generated for the Diesel generator model.Diesel_Cost_Total = Var(model.scenario, within=NonNegativeReals) # Varialbles associated to the energy balance model.Lost_Load = Var(model.scenario, model.periods, within=NonNegativeReals) # Energy not suply by the system kWh model.Energy_Curtailment = Var(model.scenario, model.periods, within=NonNegativeReals) # Curtailment of solar energy in kWh model.Scenario_Lost_Load_Cost = Var(model.scenario, within=NonNegativeReals) #### # Variables associated to the project model.Cost_Financial = Var(within=NonNegativeReals) # Financial cost of each period in USD model.Scenario_Net_Present_Cost = Var(model.scenario, within=NonNegativeReals) #### model.Initial_Inversion = Var(within=NonNegativeReals) model.Operation_Maintenance_Cost = Var(within=NonNegativeReals) model.Total_Finalcial_Cost = Var(within=NonNegativeReals) model.Battery_Reposition_Cost = Var(within=NonNegativeReals)
def Model_Creation_Integer(model): ''' This function creates the instance for the resolution of the optimization in Pyomo. The problem is solved by discretizing the efficiency curve of the generators and uses binary variables :param model: Pyomo model as defined in the Micro-Grids library. ''' from pyomo.environ import Param, RangeSet, NonNegativeReals, Var, NonNegativeIntegers from Initialize import Initialize_years, Initialize_Demand, Marginal_Cost_Generator, Start_Cost, Marginal_Cost_Generator_1, Capital_Recovery_Factor,Battery_Reposition_Cost, Initialize_Renewable_Energy # Import library with initialitation funtions for the parameters # Time parameters model.Periods = Param(within=NonNegativeReals) # Number of periods of analysis of the energy variables model.Years = Param() # Number of years of the project model.StartDate = Param() # Start date of the analisis model.PlotTime = Param() # Quantity of days that are going to be plot model.PlotDay = Param() # Start day for the plot model.Scenarios = Param() model.PlotScenario = Param() model.Renewable_Source = Param() model.Generator_Type = Param() #SETS model.periods = RangeSet(1, model.Periods) # Creation of a set from 1 to the number of periods in each year model.years = RangeSet(1, model.Years) # Creation of a set from 1 to the number of years of the project model.scenario = RangeSet(1, model.Scenarios) # Creation of a set from 1 to the numbero scenarios to analized model.renewable_source = RangeSet(1, model.Renewable_Source) model.generator_type = RangeSet(1, model.Generator_Type) # PARAMETERS # Parameters of the PV model.Renewable_Nominal_Capacity = Param(model.renewable_source, within=NonNegativeReals) model.Inverter_Efficiency_Renewable = Param(model.renewable_source, within=NonNegativeReals) model.Renewable_Invesment_Cost = Param(model.renewable_source, within=NonNegativeReals) model.Renewable_Energy_Production = Param(model.scenario, model.renewable_source, model.periods, initialize=Initialize_Renewable_Energy) #instance.Renewable_Invesment_Cost.extract_values() # Parameters of the battery bank model.Charge_Battery_Efficiency = Param() # Efficiency of the charge of the battery in % model.Discharge_Battery_Efficiency = Param() # Efficiency of the discharge of the battery in % model.Deep_of_Discharge = Param() # Deep of discharge of the battery (Deep_of_Discharge) in % model.Maximun_Battery_Charge_Time = Param(within=NonNegativeReals) # Minimun time of charge of the battery in hours model.Maximun_Battery_Discharge_Time = Param(within=NonNegativeReals) # Maximun time of discharge of the battery in hours model.Battery_Invesment_Cost = Param(within=NonNegativeReals) # Cost of battery model.Battery_Cycles = Param(within=NonNegativeReals) model.Battery_Reposition_Cost = Param(within=NonNegativeReals, initialize=Battery_Reposition_Cost) # Parametes of the diesel generator model.Generator_Min_Out_Put = Param(model.generator_type, within=NonNegativeReals) model.Generator_Efficiency = Param(model.generator_type) # Generator efficiency to trasform heat into electricity % model.Low_Heating_Value = Param(model.generator_type) # Low heating value of the diesel in W/L model.Fuel_Cost = Param(model.generator_type, within=NonNegativeReals) # Cost of diesel in USD/L model.Generator_Invesment_Cost = Param(model.generator_type,within=NonNegativeReals) # Cost of the diesel generator model.Marginal_Cost_Generator_1 = Param(model.generator_type, initialize=Marginal_Cost_Generator_1) model.Cost_Increase = Param(model.generator_type, within=NonNegativeReals) model.Generator_Nominal_Capacity = Param(model.generator_type, within=NonNegativeReals) model.Start_Cost_Generator = Param(model.generator_type, within=NonNegativeReals, initialize=Start_Cost) model.Marginal_Cost_Generator = Param(model.generator_type, initialize=Marginal_Cost_Generator) # Parameters of the Energy balance model.Energy_Demand = Param(model.scenario,model.periods, initialize=Initialize_Demand) # Energy Energy_Demand in W model.Lost_Load_Probability = Param() # Lost load probability in % model.Value_Of_Lost_Load = Param(within=NonNegativeReals) # Value of lost load in USD/W # Parameters of the proyect model.Delta_Time = Param(within=NonNegativeReals) # Time step in hours model.Project_Years = Param(model.years, initialize= Initialize_years) # Years of the project model.Maintenance_Operation_Cost_Renewable = Param(model.renewable_source, within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in % model.Maintenance_Operation_Cost_Battery = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in % model.Maintenance_Operation_Cost_Generator = Param(model.generator_type, within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in % model.Discount_Rate = Param() # Discount rate of the project in % model.Scenario_Weight = Param(model.scenario, within=NonNegativeReals) model.Capital_Recovery_Factor = Param(within=NonNegativeReals, initialize= Capital_Recovery_Factor) # VARIABLES # Variables associated to the solar panels model.Renewable_Units = Var(model.renewable_source, within=NonNegativeReals) # Variables associated to the battery bank model.Battery_Nominal_Capacity = Var(within=NonNegativeReals) # Capacity of the battery bank in Wh model.Energy_Battery_Flow_Out = Var(model.scenario,model.periods, within=NonNegativeReals) # Battery discharge energy in wh model.Energy_Battery_Flow_In = Var(model.scenario,model.periods, within=NonNegativeReals) # Battery charge energy in wh model.State_Of_Charge_Battery = Var(model.scenario,model.periods, within=NonNegativeReals) # State of Charge of the Battery in wh # Variables associated to the diesel generator model.Energy_Generator_Total = Var(model.scenario,model.generator_type, model.periods, within=NonNegativeReals) model.Integer_generator = Var(model.generator_type, within=NonNegativeIntegers) model.Generator_Total_Period_Energy = Var(model.scenario, model.generator_type, model.periods, within=NonNegativeReals) model.Generator_Energy_Integer = Var(model.scenario, model.generator_type, model.periods, within=NonNegativeIntegers) model.Last_Energy_Generator = Var(model.scenario, model.generator_type, model.periods, within=NonNegativeReals) # Varialbles associated to the energy balance model.Lost_Load = Var(model.scenario,model.periods, within=NonNegativeReals) # Energy not suply by the system kWh model.Energy_Curtailment = Var(model.scenario,model.periods, within=NonNegativeReals) # Curtailment of solar energy in kWh
import pyomo.environ from pyomo.environ import ConcreteModel, AbstractModel, Param, RangeSet, Set, BuildAction, Var, Objective, Piecewise, minimize, value from pyomo.environ import NonNegativeReals, Integers, Binary, PositiveIntegers from pyomo.opt import SolverStatus, TerminationCondition from pyomo.opt import SolverFactory from support import * #%% take care of input data machine = pd.read_excel(r"system load.xlsx") cost_para = pd.read_excel(r"cost parameter.xlsx") cost_para["Product_cost_ini"] = cost_para['a'] + cost_para['b'] * machine[ "Pmin"] + cost_para['c'] * machine["Pmin"]**2 load = pd.read_excel(r"load.xlsx") #%% create absmodel amodel = AbstractModel() amodel.generator = Set(initialize=machine["Units"]) amodel.nperiods = Param(within=PositiveIntegers, initialize=len(load)) amodel.periods = RangeSet(1, amodel.nperiods) amodel.demand = Param(amodel.periods, within=NonNegativeReals, initialize=modifyind(load['demand'])) amodel.reserve = Param(amodel.periods, within=NonNegativeReals, default=0.0, initialize=modifyind(load['demand'] * 0.1)) amodel.minout = Param(amodel.generator, within=NonNegativeReals, default=0.0, initialize=modifyind(machine["Pmin"])) amodel.maxout = Param(amodel.generator, within=NonNegativeReals, validate=check_max_power,
def test_not_var(model): model.p = Param() with pytest.raises(TypeError): homotopy(model, [model.p], [20])
def build(self): ''' Callable method for Block construction. ''' super(BTParameterData, self).build() self.cubic_type = CubicEoS.PR # Add Component objects self.benzene = Component( default={"elemental_composition": { "C": 6, "H": 6 }}) self.toluene = Component( default={"elemental_composition": { "C": 7, "H": 8 }}) # List of phase equilibrium index self.phase_equilibrium_idx = Set(initialize=[1, 2]) self.phase_equilibrium_list = \ {1: ["benzene", ("Vap", "Liq")], 2: ["toluene", ("Vap", "Liq")]} # Thermodynamic reference state self.pressure_ref = Param(mutable=True, default=101325, doc='Reference pressure [Pa]', units=pyunits.Pa) self.temperature_ref = Param(mutable=True, default=298.15, doc='Reference temperature [K]', units=pyunits.K) # Critical Properties pressure_crit_data = {'benzene': 48.9e5, 'toluene': 41.0e5} self.pressure_crit = Param(self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(pressure_crit_data), doc='Critical pressure [Pa]', units=pyunits.Pa) temperature_crit_data = {'benzene': 562.2, 'toluene': 591.8} self.temperature_crit = Param( self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(temperature_crit_data), doc='Critical temperature [K]', units=pyunits.K) # Pitzer acentricity factor omega_data = {'benzene': 0.212, 'toluene': 0.263} self.omega = Param(self.component_list, within=Reals, mutable=False, initialize=extract_data(omega_data), doc='Acentricity Factor') # Peng-Robinson binary interaction parameters kappa_data = { ('benzene', 'benzene'): 0.0000, ('benzene', 'toluene'): 0.0000, ('toluene', 'benzene'): 0.0000, ('toluene', 'toluene'): 0.0000 } self.kappa = Param(self.component_list, self.component_list, within=Reals, mutable=False, initialize=extract_data(kappa_data), doc='Peng-Robinson binary interaction parameters') # Molecular Weights mw_comp_data = {'benzene': 78.1136E-3, 'toluene': 92.1405E-3} self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), doc="molecular weight kg/mol", units=pyunits.kg / pyunits.mol) # Constants for specific heat capacity, enthalpy and entropy self.cp_mol_ig_comp_coeff_1 = Param( self.component_list, mutable=False, initialize={ 'benzene': -3.392E1, 'toluene': -2.435E1 }, doc="Parameter 1 to compute cp_mol_comp", units=pyunits.J / pyunits.mol / pyunits.K) self.cp_mol_ig_comp_coeff_2 = Param( self.component_list, mutable=False, initialize={ 'benzene': 4.739E-1, 'toluene': 5.125E-1 }, doc="Parameter 2 to compute cp_mol_comp", units=pyunits.J / pyunits.mol / pyunits.K**2) self.cp_mol_ig_comp_coeff_3 = Param( self.component_list, mutable=False, initialize={ 'benzene': -3.017E-4, 'toluene': -2.765E-4 }, doc="Parameter 3 to compute cp_mol_comp", units=pyunits.J / pyunits.mol / pyunits.K**3) self.cp_mol_ig_comp_coeff_4 = Param( self.component_list, mutable=False, initialize={ 'benzene': 7.130E-8, 'toluene': 4.911E-8 }, doc="Parameter 4 to compute cp_mol_comp", units=pyunits.J / pyunits.mol / pyunits.K**4) # Standard heats of formation # Source: NIST Webbook, https://webbook.nist.gov # Retrieved 25th September 2019 dh_form_data = {'benzene': 82.9e3, 'toluene': 50.1e3} self.enth_mol_form_ref = Param(self.component_list, mutable=False, initialize=extract_data(dh_form_data), doc="Standard heats of formation", units=pyunits.J / pyunits.mol) # Standard entropy of formation # Source: Engineering Toolbox, https://www.engineeringtoolbox.com # Retrieved 25th September, 2019 ds_form_data = {'benzene': -269, 'toluene': -321} self.entr_mol_form_ref = Param(self.component_list, mutable=False, initialize=extract_data(ds_form_data), doc="Standard entropy of formation", units=pyunits.J / pyunits.mol / pyunits.K) # Antoine coefficients for ideal vapour (units: bar, K) # This is needed for initial guesses of bubble and dew points self.antoine_coeff_A = Param( self.component_list, mutable=False, initialize={ 'benzene': 4.202, 'toluene': 4.216 }, doc="Antoine A Parameter to calculate pressure_sat", units=pyunits.dimensionless) self.antoine_coeff_B = Param( self.component_list, mutable=False, initialize={ 'benzene': 1322, 'toluene': 1435 }, doc="Antoine B Parameter to calculate pressure_sat", units=pyunits.K) self.antoine_coeff_C = Param( self.component_list, mutable=False, initialize={ 'benzene': -38.56, 'toluene': -43.33 }, doc="Antoine C Parameter to calculate pressure_sat", units=pyunits.K)
def build(self): ''' Callable method for Block construction. ''' super(HDAParameterData, self).build() self.state_block_class = IdealStateBlock self.component_list = Set( initialize=['benzene', 'toluene', 'hydrogen', 'methane']) self.phase_list = Set(initialize=['Liq', 'Vap'], ordered=True) # List of components in each phase (optional) self.phase_comp = { "Liq": self.component_list, "Vap": self.component_list } # List of phase equilibrium index self.phase_equilibrium_idx = Set(initialize=[1, 2, 3, 4, 5]) self.phase_equilibrium_list = \ {1: ["benzene", ("Vap", "Liq")], 2: ["toluene", ("Vap", "Liq")], 3: ["hydrogen", ("Vap", "Liq")], 4: ["methane", ("Vap", "Liq")], 5: ["diphenyl", ("Vap", "Liq")]} # Thermodynamic reference state self.pressure_ref = Param(mutable=True, default=101325, doc='Reference pressure [Pa]') self.temperature_ref = Param(mutable=True, default=298.15, doc='Reference temperature [K]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid pressure_crit_data = { 'benzene': 48.9e5, 'toluene': 41e5, 'hydrogen': 12.9e5, 'methane': 46e5, 'diphenyl': 38.5e5 } self.pressure_crit = Param(self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(pressure_crit_data), doc='Critical pressure [Pa]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid temperature_crit_data = { 'benzene': 562.2, 'toluene': 591.8, 'hydrogen': 33.0, 'methane': 190.4, 'diphenyl': 789 } self.temperature_crit = Param( self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(temperature_crit_data), doc='Critical temperature [K]') # Gas Constant self.gas_const = Param(within=NonNegativeReals, mutable=False, default=8.314, doc='Gas Constant [J/mol.K]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid mw_comp_data = { 'benzene': 78.1136E-3, 'toluene': 92.1405E-3, 'hydrogen': 2.016e-3, 'methane': 16.043e-3, 'diphenyl': 154.212e-4 } self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), doc="molecular weight Kg/mol") # Constants for liquid densities # Source: Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) dens_liq_data = { ('benzene', '1'): 1.0162, ('benzene', '2'): 0.2655, ('benzene', '3'): 562.16, ('benzene', '4'): 0.28212, ('toluene', '1'): 0.8488, ('toluene', '2'): 0.26655, ('toluene', '3'): 591.8, ('toluene', '4'): 0.2878, ('hydrogen', '1'): 5.414, ('hydrogen', '2'): 0.34893, ('hydrogen', '3'): 33.19, ('hydrogen', '4'): 0.2706, ('methane', '1'): 2.9214, ('methane', '2'): 0.28976, ('methane', '3'): 190.56, ('methane', '4'): 0.28881, ('diphenyl', '1'): 0.5039, ('diphenyl', '2'): 0.25273, ('diphenyl', '3'): 789.26, ('diphenyl', '4'): 0.281 } self.dens_liq_params = Param( self.component_list, ['1', '2', '3', '4'], mutable=False, initialize=extract_data(dens_liq_data), doc="Parameters to compute liquid densities") # Boiling point at standard pressure # Source: Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) bp_data = { ('benzene'): 353.25, ('toluene'): 383.95, ('hydrogen'): 20.45, ('methane'): 111.75, ('diphenyl'): 528.05 } self.temperature_boil = Param( self.component_list, mutable=False, initialize=extract_data(bp_data), doc="Pure component boiling points at standard pressure [K]") # Constants for specific heat capacity, enthalpy # Sources: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid # Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) cp_ig_data = { ('Liq', 'benzene', '1'): 1.29E5, ('Liq', 'benzene', '2'): -1.7E2, ('Liq', 'benzene', '3'): 6.48E-1, ('Liq', 'benzene', '4'): 0, ('Liq', 'benzene', '5'): 0, ('Vap', 'benzene', '1'): -3.392E1, ('Vap', 'benzene', '2'): 4.739E-1, ('Vap', 'benzene', '3'): -3.017E-4, ('Vap', 'benzene', '4'): 7.130E-8, ('Vap', 'benzene', '5'): 0, ('Liq', 'toluene', '1'): 1.40E5, ('Liq', 'toluene', '2'): -1.52E2, ('Liq', 'toluene', '3'): 6.95E-1, ('Liq', 'toluene', '4'): 0, ('Liq', 'toluene', '5'): 0, ('Vap', 'toluene', '1'): -2.435E1, ('Vap', 'toluene', '2'): 5.125E-1, ('Vap', 'toluene', '3'): -2.765E-4, ('Vap', 'toluene', '4'): 4.911E-8, ('Vap', 'toluene', '5'): 0, ('Liq', 'hydrogen', '1'): 0, # 6.6653e1, ('Liq', 'hydrogen', '2'): 0, # 6.7659e3, ('Liq', 'hydrogen', '3'): 0, # -1.2363e2, ('Liq', 'hydrogen', '4'): 0, # 4.7827e2, # Eqn 2 ('Liq', 'hydrogen', '5'): 0, ('Vap', 'hydrogen', '1'): 2.714e1, ('Vap', 'hydrogen', '2'): 9.274e-3, ('Vap', 'hydrogen', '3'): -1.381e-5, ('Vap', 'hydrogen', '4'): 7.645e-9, ('Vap', 'hydrogen', '5'): 0, ('Liq', 'methane', '1'): 0, # 6.5708e1, ('Liq', 'methane', '2'): 0, # 3.8883e4, ('Liq', 'methane', '3'): 0, # -2.5795e2, ('Liq', 'methane', '4'): 0, # 6.1407e2, # Eqn 2 ('Liq', 'methane', '5'): 0, ('Vap', 'methane', '1'): 1.925e1, ('Vap', 'methane', '2'): 5.213e-2, ('Vap', 'methane', '3'): 1.197e-5, ('Vap', 'methane', '4'): -1.132e-8, ('Vap', 'methane', '5'): 0, ('Liq', 'diphenyl', '1'): 1.2177e5, ('Liq', 'diphenyl', '2'): 4.2930e2, ('Liq', 'diphenyl', '3'): 0, ('Liq', 'diphenyl', '4'): 0, ('Liq', 'diphenyl', '5'): 0, ('Vap', 'diphenyl', '1'): -9.707e1, ('Vap', 'diphenyl', '2'): 1.106e0, ('Vap', 'diphenyl', '3'): -8.855e-4, ('Vap', 'diphenyl', '4'): 2.790e-7, ('Vap', 'diphenyl', '5'): 0 } self.cp_ig = Param(self.phase_list, self.component_list, ['1', '2', '3', '4', '5'], mutable=False, initialize=extract_data(cp_ig_data), doc="parameters to compute Cp_comp") # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid # fitted to Antoine form # H2, Methane from NIST webbook pressure_sat_coeff_data = { ('benzene', 'A'): 4.202, ('benzene', 'B'): 1322, ('benzene', 'C'): -38.56, ('toluene', 'A'): 4.216, ('toluene', 'B'): 1435, ('toluene', 'C'): -43.33, ('hydrogen', 'A'): 3.543, ('hydrogen', 'B'): 99.40, ('hydrogen', 'C'): 7.726, ('methane', 'A'): 3.990, ('methane', 'B'): 443.0, ('methane', 'C'): -0.49, ('diphenyl', 'A'): 4.345, ('diphenyl', 'B'): 1988, ('diphenyl', 'C'): -70.82 } self.pressure_sat_coeff = Param( self.component_list, ['A', 'B', 'C'], mutable=False, initialize=extract_data(pressure_sat_coeff_data), doc="parameters to compute Cp_comp") # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid dh_vap = { 'benzene': 3.387e4, 'toluene': 3.8262e4, 'hydrogen': 0, 'methane': 0, "diphenyl": 6.271e4 } self.dh_vap = Param(self.component_list, mutable=False, initialize=extract_data(dh_vap), doc="heat of vaporization")
def build(self): """ Callable method for Block construction. """ super(WaterParameterData, self).build() self._state_block_class = WaterStateBlock # components self.H2O = Component() # phases self.Liq = LiquidPhase() self.Vap = VaporPhase() """ References This package was developed from the following references: - K.G.Nayar, M.H.Sharqawy, L.D.Banchik, and J.H.Lienhard V, "Thermophysical properties of seawater: A review and new correlations that include pressure dependence,"Desalination, Vol.390, pp.1 - 24, 2016. doi: 10.1016/j.desal.2016.02.024(preprint) - Mostafa H.Sharqawy, John H.Lienhard V, and Syed M.Zubair, "Thermophysical properties of seawater: A review of existing correlations and data,"Desalination and Water Treatment, Vol.16, pp.354 - 380, April 2010. (2017 corrections provided at http://web.mit.edu/seawater) """ # Parameters # molecular weight self.mw_comp = Param( self.component_list, mutable=False, initialize=18.01528e-3, units=pyunits.kg / pyunits.mol, doc="Molecular weight", ) # Liq mass density parameters, eq. 8 in Sharqawy et al. (2010) dens_units = pyunits.kg / pyunits.m**3 t_inv_units = pyunits.K**-1 s_inv_units = pyunits.kg / pyunits.g self.dens_mass_param_A1 = Var( within=Reals, initialize=9.999e2, units=dens_units, doc="Mass density parameter A1", ) self.dens_mass_param_A2 = Var( within=Reals, initialize=2.034e-2, units=dens_units * t_inv_units, doc="Mass density parameter A2", ) self.dens_mass_param_A3 = Var( within=Reals, initialize=-6.162e-3, units=dens_units * t_inv_units**2, doc="Mass density parameter A3", ) self.dens_mass_param_A4 = Var( within=Reals, initialize=2.261e-5, units=dens_units * t_inv_units**3, doc="Mass density parameter A4", ) self.dens_mass_param_A5 = Var( within=Reals, initialize=-4.657e-8, units=dens_units * t_inv_units**4, doc="Mass density parameter A5", ) # Vap mass density parameters (approximating using ideal gas) self.dens_mass_param_mw = Var( within=Reals, initialize=18.01528e-3, units=pyunits.kg / pyunits.mol, doc="Mass density parameter molecular weight", ) self.dens_mass_param_R = Var( within=Reals, initialize=8.31462618, units=pyunits.J / pyunits.mol / pyunits.K, doc="Mass density parameter universal gas constant", ) # vapor pressure parameters, eq. 5 and 6 in Nayar et al.(2016) self.pressure_sat_param_psatw_A1 = Var( within=Reals, initialize=-5.8002206e3, units=pyunits.K, doc="Vapor pressure of pure water parameter A1", ) self.pressure_sat_param_psatw_A2 = Var( within=Reals, initialize=1.3914993, units=pyunits.dimensionless, doc="Vapor pressure of pure water parameter A2", ) self.pressure_sat_param_psatw_A3 = Var( within=Reals, initialize=-4.8640239e-2, units=t_inv_units, doc="Vapor pressure of pure water parameter A3", ) self.pressure_sat_param_psatw_A4 = Var( within=Reals, initialize=4.1764768e-5, units=t_inv_units**2, doc="Vapor pressure of pure water parameter A4", ) self.pressure_sat_param_psatw_A5 = Var( within=Reals, initialize=-1.4452093e-8, units=t_inv_units**3, doc="Vapor pressure of pure water parameter A5", ) self.pressure_sat_param_psatw_A6 = Var( within=Reals, initialize=6.5459673, units=pyunits.dimensionless, doc="Vapor pressure of pure water parameter A6", ) # specific enthalpy parameters, eq. 55 and 43 in Sharqawy et al. (2010) enth_mass_units = pyunits.J / pyunits.kg self.enth_mass_param_A1 = Var( within=Reals, initialize=141.355, units=enth_mass_units, doc="Specific enthalpy parameter A1", ) self.enth_mass_param_A2 = Var( within=Reals, initialize=4202.07, units=enth_mass_units * t_inv_units, doc="Specific enthalpy parameter A2", ) self.enth_mass_param_A3 = Var( within=Reals, initialize=-0.535, units=enth_mass_units * t_inv_units**2, doc="Specific enthalpy parameter A3", ) self.enth_mass_param_A4 = Var( within=Reals, initialize=0.004, units=enth_mass_units * t_inv_units**3, doc="Specific enthalpy parameter A4", ) # self.enth_mass_param_B1 = Var( # within=Reals, initialize=-2.348e4, units=enth_mass_units, # doc='Specific enthalpy parameter B1') # self.enth_mass_param_B2 = Var( # within=Reals, initialize=3.152e5, units=enth_mass_units, # doc='Specific enthalpy parameter B2') # self.enth_mass_param_B3 = Var( # within=Reals, initialize=2.803e6, units=enth_mass_units, # doc='Specific enthalpy parameter B3') # self.enth_mass_param_B4 = Var( # within=Reals, initialize=-1.446e7, units=enth_mass_units, # doc='Specific enthalpy parameter B4') # self.enth_mass_param_B5 = Var( # within=Reals, initialize=7.826e3, units=enth_mass_units * t_inv_units, # doc='Specific enthalpy parameter B5') # self.enth_mass_param_B6 = Var( # within=Reals, initialize=-4.417e1, units=enth_mass_units * t_inv_units**2, # doc='Specific enthalpy parameter B6') # self.enth_mass_param_B7 = Var( # within=Reals, initialize=2.139e-1, units=enth_mass_units * t_inv_units**3, # doc='Specific enthalpy parameter B7') # self.enth_mass_param_B8 = Var( # within=Reals, initialize=-1.991e4, units=enth_mass_units * t_inv_units, # doc='Specific enthalpy parameter B8') # self.enth_mass_param_B9 = Var( # within=Reals, initialize=2.778e4, units=enth_mass_units * t_inv_units, # doc='Specific enthalpy parameter B9') # self.enth_mass_param_B10 = Var( # within=Reals, initialize=9.728e1, units=enth_mass_units * t_inv_units**2, # doc='Specific enthalpy parameter B10') # specific heat parameters from eq (9) in Sharqawy et al. (2010) cp_units = pyunits.J / (pyunits.kg * pyunits.K) self.cp_phase_param_A1 = Var( within=Reals, initialize=5.328, units=cp_units, doc="Specific heat of seawater parameter A1", ) # self.cp_phase_param_A2 = Var( # within=Reals, initialize=-9.76e-2, units=cp_units * s_inv_units, # doc='Specific heat of seawater parameter A2') # self.cp_phase_param_A3 = Var( # within=Reals, initialize=4.04e-4, units=cp_units * s_inv_units**2, # doc='Specific heat of seawater parameter A3') self.cp_phase_param_B1 = Var( within=Reals, initialize=-6.913e-3, units=cp_units * t_inv_units, doc="Specific heat of seawater parameter B1", ) # self.cp_phase_param_B2 = Var( # within=Reals, initialize=7.351e-4, units=cp_units * s_inv_units * t_inv_units, # doc='Specific heat of seawater parameter B2') # self.cp_phase_param_B3 = Var( # within=Reals, initialize=-3.15e-6, units=cp_units * s_inv_units**2 * t_inv_units, # doc='Specific heat of seawater parameter B3') self.cp_phase_param_C1 = Var( within=Reals, initialize=9.6e-6, units=cp_units * t_inv_units**2, doc="Specific heat of seawater parameter C1", ) # self.cp_phase_param_C2 = Var( # within=Reals, initialize=-1.927e-6, units=cp_units * s_inv_units * t_inv_units**2, # doc='Specific heat of seawater parameter C2') # self.cp_phase_param_C3 = Var( # within=Reals, initialize=8.23e-9, units=cp_units * s_inv_units**2 * t_inv_units**2, # doc='Specific heat of seawater parameter C3') self.cp_phase_param_D1 = Var( within=Reals, initialize=2.5e-9, units=cp_units * t_inv_units**3, doc="Specific heat of seawater parameter D1", ) # self.cp_phase_param_D2 = Var( # within=Reals, initialize=1.666e-9, units=cp_units * s_inv_units * t_inv_units**3, # doc='Specific heat of seawater parameter D2') # self.cp_phase_param_D3 = Var( # within=Reals, initialize=-7.125e-12, units=cp_units * s_inv_units**2 * t_inv_units**3, # doc='Specific heat of seawater parameter D3') # Specific heat parameters for Cp vapor from NIST Webbook # Chase, M.W., Jr., NIST-JANAF Themochemical Tables, Fourth Edition, J. Phys. Chem. Ref. Data, Monograph 9, 1998, 1-1951 self.cp_vap_param_A = Var( within=Reals, initialize=30.09200 / 18.01528e-3, units=cp_units, doc="Specific heat of water vapor parameter A", ) self.cp_vap_param_B = Var( within=Reals, initialize=6.832514 / 18.01528e-3, units=cp_units * t_inv_units, doc="Specific heat of water vapor parameter B", ) self.cp_vap_param_C = Var( within=Reals, initialize=6.793435 / 18.01528e-3, units=cp_units * t_inv_units**2, doc="Specific heat of water vapor parameter C", ) self.cp_vap_param_D = Var( within=Reals, initialize=-2.534480 / 18.01528e-3, units=cp_units * t_inv_units**3, doc="Specific heat of water vapor parameter D", ) self.cp_vap_param_E = Var( within=Reals, initialize=0.082139 / 18.01528e-3, units=cp_units * t_inv_units**-2, doc="Specific heat of water vapor parameter E", ) # latent heat of pure water parameters from eq. 54 in Sharqawy et al. (2010) self.dh_vap_w_param_0 = Var( within=Reals, initialize=2.501e6, units=enth_mass_units, doc="Latent heat of pure water parameter 0", ) self.dh_vap_w_param_1 = Var( within=Reals, initialize=-2.369e3, units=cp_units, doc="Latent heat of pure water parameter 1", ) self.dh_vap_w_param_2 = Var( within=Reals, initialize=2.678e-1, units=enth_mass_units * t_inv_units**2, doc="Latent heat of pure water parameter 2", ) self.dh_vap_w_param_3 = Var( within=Reals, initialize=-8.103e-3, units=enth_mass_units * t_inv_units**3, doc="Latent heat of pure water parameter 3", ) self.dh_vap_w_param_4 = Var( within=Reals, initialize=-2.079e-5, units=enth_mass_units * t_inv_units**4, doc="Latent heat of pure water parameter 4", ) # traditional parameters are the only Vars currently on the block and should be fixed for v in self.component_objects(Var): v.fix() # ---default scaling--- self.set_default_scaling("temperature", 1e-2) self.set_default_scaling("pressure", 1e-5) self.set_default_scaling("dens_mass_phase", 1e-3, index="Liq") self.set_default_scaling("dens_mass_phase", 1, index="Vap") # self.set_default_scaling('dens_mass_solvent', 1e-3) self.set_default_scaling("enth_mass_phase", 1e-5, index="Liq") self.set_default_scaling("enth_mass_phase", 1e-6, index="Vap") self.set_default_scaling("pressure_sat", 1e-5) self.set_default_scaling("cp_phase", 1e-3, index="Liq") self.set_default_scaling("cp_phase", 1e-3, index="Vap") self.set_default_scaling("dh_vap", 1e-6)
def build(self): """Callable method for Block construction.""" super(IdealStateBlockData, self).build() # Add state variables self.flow_mol_phase_comp = Var( self._params.phase_list, self._params.component_list, initialize=0.5, bounds=(1e-8, 100), doc='Phase-component molar flow rates [mol/s]') self.pressure = Var(initialize=101325, bounds=(101325, 400000), domain=NonNegativeReals, doc='State pressure [Pa]') self.temperature = Var(initialize=298.15, bounds=(298.15, 1000), domain=NonNegativeReals, doc='State temperature [K]') # Add supporting variables def flow_mol_phase(b, p): return sum(b.flow_mol_phase_comp[p, j] for j in b._params.component_list) self.flow_mol_phase = Expression(self._params.phase_list, rule=flow_mol_phase, doc='Phase molar flow rates [mol/s]') def flow_mol(b): return sum(b.flow_mol_phase_comp[p, j] for j in b._params.component_list for p in b._params.phase_list) self.flow_mol = Expression(rule=flow_mol, doc='Total molar flowrate [mol/s]') def mole_frac_phase_comp(b, p, j): return b.flow_mol_phase_comp[p, j] / b.flow_mol_phase[p] self.mole_frac_phase_comp = Expression(self._params.phase_list, self._params.component_list, rule=mole_frac_phase_comp, doc='Phase mole fractions [-]') def mole_frac_comp(b, j): return (sum(b.flow_mol_phase_comp[p, j] for p in b._params.phase_list) / b.flow_mol) self.mole_frac_comp = Expression(self._params.component_list, rule=mole_frac_comp, doc='Mixture mole fractions [-]') # Reaction Stoichiometry add_object_reference(self, "phase_equilibrium_list_ref", self._params.phase_equilibrium_list) if (self.config.has_phase_equilibrium and self.config.defined_state is False): # Definition of equilibrium temperature for smooth VLE self._teq = Var( initialize=self.temperature.value, doc='Temperature for calculating phase equilibrium') self._t1 = Var(initialize=self.temperature.value, doc='Intermediate temperature for calculating Teq') self.eps_1 = Param(default=0.01, mutable=True, doc='Smoothing parameter for Teq') self.eps_2 = Param(default=0.0005, mutable=True, doc='Smoothing parameter for Teq') # PSE paper Eqn 13 def rule_t1(b): return b._t1 == 0.5 * ( b.temperature + b.temperature_bubble + sqrt((b.temperature - b.temperature_bubble)**2 + b.eps_1**2)) self._t1_constraint = Constraint(rule=rule_t1) # PSE paper Eqn 14 # TODO : Add option for supercritical extension def rule_teq(b): return b._teq == 0.5 * (b._t1 + b.temperature_dew - sqrt( (b._t1 - b.temperature_dew)**2 + b.eps_2**2)) self._teq_constraint = Constraint(rule=rule_teq) def rule_tr_eq(b, i): return b._teq / b._params.temperature_crit[i] self._tr_eq = Expression(self._params.component_list, rule=rule_tr_eq, doc='Component reduced temperatures [-]') def rule_equilibrium(b, i): return b.fug_vap[i] == b.fug_liq[i] self.equilibrium_constraint = Constraint( self._params.component_list, rule=rule_equilibrium)
def build(self): ''' Callable method for Block construction. ''' super(PhysicalParameterData, self).build() self._state_block_class = SolidPhaseStateBlock # Create Phase object self.Sol = SolidPhase() # Create Component objects self.Fe2O3 = Component() self.Fe3O4 = Component() self.Al2O3 = Component() # ------------------------------------------------------------------------- """ Pure solid component properties""" # Mol. weights of solid components - units = kg/mol. ref: NIST webbook mw_comp_dict = {'Fe2O3': 0.15969, 'Fe3O4': 0.231533, 'Al2O3': 0.10196} self.mw_comp = Param( self.component_list, mutable=False, initialize=mw_comp_dict, doc="Molecular weights of solid components [kg/mol]", units=pyunits.kg / pyunits.m**3) # Skeletal density of solid components - units = kg/m3. ref: NIST dens_mass_comp_skeletal_dict = { 'Fe2O3': 5250, 'Fe3O4': 5000, 'Al2O3': 3987 } self.dens_mass_comp_skeletal = Param( self.component_list, mutable=False, initialize=dens_mass_comp_skeletal_dict, doc='Skeletal density of solid components [kg/m3]', units=pyunits.kg / pyunits.m**3) # Ideal gas spec. heat capacity parameters(Shomate) of # components - ref: NIST webbook. Shomate equations from NIST. # Parameters A-E are used for cp calcs while A-H are used for enthalpy # calc. # 1e3*cp_comp = A + B*T + C*T^2 + D*T^3 + E/(T^2) # where T = Temperature (K)/1000, and cp_comp = (kJ/mol.K) # H_comp = H - H(298.15) = A*T + B*T^2/2 + C*T^3/3 + # D*T^4/4 - E/T + F - H where T = Temp (K)/1000 and H_comp = (kJ/mol) cp_param_dict = { ('Al2O3', 1): 102.4290, ('Al2O3', 2): 38.74980, ('Al2O3', 3): -15.91090, ('Al2O3', 4): 2.628181, ('Al2O3', 5): -3.007551, ('Al2O3', 6): -1717.930, ('Al2O3', 7): 146.9970, ('Al2O3', 8): -1675.690, ('Fe3O4', 1): 200.8320000, ('Fe3O4', 2): 1.586435e-7, ('Fe3O4', 3): -6.661682e-8, ('Fe3O4', 4): 9.452452e-9, ('Fe3O4', 5): 3.18602e-8, ('Fe3O4', 6): -1174.1350000, ('Fe3O4', 7): 388.0790000, ('Fe3O4', 8): -1120.8940000, ('Fe2O3', 1): 110.9362000, ('Fe2O3', 2): 32.0471400, ('Fe2O3', 3): -9.1923330, ('Fe2O3', 4): 0.9015060, ('Fe2O3', 5): 5.4336770, ('Fe2O3', 6): -843.1471000, ('Fe2O3', 7): 228.3548000, ('Fe2O3', 8): -825.5032000 } self.cp_param = Param(self.component_list, range(1, 10), mutable=False, initialize=cp_param_dict, doc="Shomate equation heat capacity parameters") # Std. heat of formation of comp. - units = kJ/(mol comp) - ref: NIST enth_mol_form_comp_dict = { 'Fe2O3': -825.5032, 'Fe3O4': -1120.894, 'Al2O3': -1675.690 } self.enth_mol_form_comp = Param( self.component_list, mutable=False, initialize=enth_mol_form_comp_dict, doc="Component molar heats of formation [kJ/mol]", units=pyunits.kJ / pyunits.mol) # ------------------------------------------------------------------------- """ Mixed solid properties""" # These are setup as fixed vars to allow for parameter estimation # Particle size self.particle_dia = Var(domain=Reals, initialize=1.5e-3, doc='Diameter of solid particles [m]', units=pyunits.m) self.particle_dia.fix() # TODO -provide reference # Minimum fluidization velocity - EPAT value used for Davidson model self.velocity_mf = Var(domain=Reals, initialize=0.039624, doc='Velocity at minimum fluidization [m/s]', units=pyunits.m / pyunits.s) self.velocity_mf.fix() # Minimum fluidization voidage - educated guess as rough # estimate from ergun equation results (0.4) are suspicious self.voidage_mf = Var(domain=Reals, initialize=0.45, doc='Voidage at minimum fluidization [-]', units=pyunits.m**3 / pyunits.m**3) self.voidage_mf.fix() # Particle thermal conductivity self.therm_cond_sol = Var( domain=Reals, initialize=12.3e-3, doc='Thermal conductivity of solid particles [kJ/m.K.s]', units=pyunits.kJ / pyunits.m / pyunits.K / pyunits.s) self.therm_cond_sol.fix()
def _temperature_bubble(self): self.temperature_bubble = Param(initialize=33.0, doc="Bubble point temperature (K)")
def add_model_components(m, d, scenario_directory, subproblem, stage): """ """ # Price by market and timepoint # Prices are allowed to be negative m.market_price = Param(m.MARKETS, m.TMPS, within=Reals)
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Sets | +=========================================================================+ | | :code:`CRBN_PRJS` | | | *Within*: :code:`PROJECTS` | | | | Two set of carbonaceous projects we need to track for the carbon cap. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Required Input Params | +=========================================================================+ | | :code:`carbon_cap_zone` | | | *Defined over*: :code:`CRBN_PRJS` | | | *Within*: :code:`CARBON_CAP_ZONES` | | | | This param describes the carbon cap zone for each carbonaceous project. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Derived Sets | +=========================================================================+ | | :code:`CRBN_PRJS_BY_CARBON_CAP_ZONE` | | | *Defined over*: :code:`CARBON_CAP_ZONES` | | | *Within*: :code:`CRBN_PRJS` | | | | Indexed set that describes the list of carbonaceous projects for each | | carbon cap zone. | +-------------------------------------------------------------------------+ | | :code:`CRBN_PRJ_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | Two-dimensional set that defines all project-timepoint combinations | | when a carbonaceous project can be operational. | +-------------------------------------------------------------------------+ """ # Sets ########################################################################### m.CRBN_PRJS = Set(within=m.PROJECTS) # Input Params ########################################################################### m.carbon_cap_zone = Param(m.CRBN_PRJS, within=m.CARBON_CAP_ZONES) # Derived Sets ########################################################################### m.CRBN_PRJS_BY_CARBON_CAP_ZONE = Set( m.CARBON_CAP_ZONES, within=m.CRBN_PRJS, initialize=lambda mod, co2_z: subset_init_by_param_value( mod, "CRBN_PRJS", "carbon_cap_zone", co2_z), ) m.CRBN_PRJ_OPR_TMPS = Set( within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.CRBN_PRJS], )
def _dens_mass(self): self.dens_mass = Param(initialize=self.params.dens_mass_default, units=pyunits.kg / pyunits.m**3, mutable=True, doc="Mass density of flow")
def _solve_sigma_given_delta(var_est_object, solver, **kwds): """Solves the maximum likelihood formulation to determine the model variance from a given device variance. This method is not intended to be used by users directly Args: delta (float): the device variance squared tee (bool,optional): flag to tell the optimizer whether to stream output to the terminal or not profile_time (bool,optional): flag to tell pyomo to time the construction and solution of the model. Default False subset_lambdas (array_like,optional): Set of wavelengths to used in initialization problem (Weifeng paper). Default all wavelengths. solver_opts (dict, optional): dictionary containing solver options for IPOPT Returns: residuals (float): the objective function value from the optimization variancesdict (dict): dictionary containing the model variance values stop_it (bool): boolean indicator showing whether no solution was found (True) or if there is a solution (False) solver_results: Variance estimation model results, similar to VarianceEstimator results from previous method """ solver_opts = kwds.pop('solver_opts', dict()) tee = kwds.pop('tee', False) set_A = kwds.pop('subset_lambdas', list()) profile_time = kwds.pop('profile_time', False) delta = kwds.pop('delta', dict()) species_list = kwds.pop('subset_components', None) model = var_est_object.model.clone() if not set_A: set_A = var_est_object._meas_lambdas if not var_est_object._sublist_components: list_components = [] if species_list is None: list_components = [k for k in var_est_object._mixture_components] else: for k in species_list: if k in var_est_object._mixture_components: list_components.append(k) else: warnings.warn( "Ignored {} since is not a mixture component of the model" .format(k)) var_est_object._sublist_components = list_components var_est_object._warn_if_D_negative() ntp = len(var_est_object._meas_times) obj = 0.0 for t in var_est_object._meas_times: for l in set_A: D_bar = sum(var_est_object.model.C[t, k] * var_est_object.model.S[l, k] for k in var_est_object.component_set) obj += 0.5 / delta * (var_est_object.model.D[t, l] - D_bar)**2 inlog = {k: 0 for k in var_est_object.component_set} var_est_object.model.eps = Param(initialize=1e-8) variancesdict = {k: 0 for k in var_est_object.component_set} for t in var_est_object._meas_times: for k in var_est_object.component_set: inlog[k] += ((var_est_object.model.C[t, k] - var_est_object.model.Z[t, k])**2) for k in var_est_object.component_set: obj += 0.5 * ntp * log(inlog[k] / ntp + var_est_object.model.eps) var_est_object.model.init_objective = Objective(expr=obj) opt = SolverFactory(solver) for key, val in solver_opts.items(): opt.options[key] = val try: solver_results = opt.solve(var_est_object.model, tee=tee, report_timing=profile_time) residuals = (value(var_est_object.model.init_objective)) for t in var_est_object._allmeas_times: for k in var_est_object.component_set: variancesdict[k] += 1 / ntp * ( (value(var_est_object.model.C[t, k]) - value(var_est_object.model.Z[t, k]))**2) print("Variances") for k in var_est_object.component_set: print(k, variancesdict[k]) print("Parameter estimates") for k, v in var_est_object.model.P.items(): print(k, v.value) stop_it = False except: print("FAILED AT THIS ITERATION") variancesdict = None residuals = 0 stop_it = True solver_results = None for k, v in var_est_object.model.P.items(): print(k, v.value) var_est_object.model = model for k, v in var_est_object.model.P.items(): print(k, v.value) var_est_object.model.del_component('init_objective') var_est_object.model.del_component('eps') return residuals, variancesdict, stop_it, solver_results
def build_model(): m = ConcreteModel() seed(1) # Fix seed to generate same parameters and solution every time m.T_max = randint(10, 10) m.T = RangeSet(m.T_max) # Variables m.s = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='stock') m.x = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='purchased') m.c = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='cost') m.f = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='feed') m.max_q_idx = RangeSet(m.T_max) # Randomly generated parameters m.D = Param(m.T, doc='demand', initialize=dict((t, randint(50, 100)) for t in m.T)) m.alpha = Param(m.T, doc='storage cost', initialize=dict((t, randint(5, 20)) for t in m.T)) m.gamma = Param(m.T, doc='base buying cost', initialize=dict((t, randint(10, 30)) for t in m.T)) m.beta_B = Param(m.T, doc='bulk discount', initialize=dict((t, randint(50, 500)/1000) for t in m.T)) m.F_B_lo = Param(m.T, doc='bulk minimum purchase amount', initialize=dict((t, randint(50, 100)) for t in m.T)) m.beta_L = Param(m.T, m.max_q_idx, initialize=dict(((t, q), randint(10, 999)/1000) for t in m.T for q in m.max_q_idx), doc='long-term discount') m.F_L_lo = Param(m.T, m.max_q_idx, initialize=dict(((t, q), randint(50, 100)) for t in m.T for q in m.max_q_idx), doc='long-term minimum purchase amount') # Contract choices 'standard', 'bulk' and long term contracts '0','1',... time_time_choices = [(t1, str(t2)) for t1, t2 in m.T * m.T if t2 <= m.T_max - t1] time_special_choices = [(t, s) for t in m.T for s in {'S', 'B', '0'}] m.contract_time_choices = Set(initialize=time_time_choices + time_special_choices) m.disjunct_choices = Set( initialize=['S', 'B', *[str(t) for t in range(m.T_max)]]) m.disjuncts = Disjunct(m.contract_time_choices) m.Y = BooleanVar(m.contract_time_choices) for t, c in m.contract_time_choices: m.Y[t, c].associate_binary_var(m.disjuncts[t, c].indicator_var) # Create disjuncts for contracts in each timeset for t in m.T: m.disjuncts[t, 'S'].cost = Constraint(expr=m.c[t] == m.gamma[t]*m.x[t]) m.disjuncts[t, 'B'].cost = Constraint( expr=m.c[t] == (1-m.beta_B[t])*m.gamma[t]*m.x[t]) m.disjuncts[t, 'B'].amount = Constraint( expr=m.x[t] >= m.F_B_lo[t]) m.disjuncts[t, '0'].c = Constraint(expr=0 <= m.c[t]) for q in range(1, m.T_max-t+1): m.disjuncts[t, str(q)].t_idx = RangeSet(t, t+q) m.disjuncts[t, str(q)].cost = Constraint(m.disjuncts[t, str(q)].t_idx) m.disjuncts[t, str(q)].amount = Constraint(m.disjuncts[t, str(q)].t_idx) for t_ in m.disjuncts[t, str(q)].t_idx: m.disjuncts[t, str(q)].cost[t_] =\ m.c[t_] == (1-m.beta_L[t, q])*m.gamma[t]*m.x[t_] m.disjuncts[t, str(q)].amount[t_] =\ m.x[t_] >= m.F_L_lo[t, q] # Create disjunctions @m.Disjunction(m.T, xor=True) def disjunctions(m, t): return [m.disjuncts[t, 'S'], m.disjuncts[t, 'B'], m.disjuncts[t, '0'], *[m.disjuncts[t, str(q)] for q in range(1, m.T_max-t+1)]] # Connect the disjuncts indicator variables using logical expressions m.logical_blocks = Block(range(1, m.T_max+1)) # Enforce absence of existing long-term contract m.logical_blocks[1].not_y_1_0 = LogicalConstraint(expr=~m.Y[1, '0'], doc="no pre-existing long-term contract") # Long-term contract implies '0'-disjunct in following timesteps for t in range(2, m.T_max+1): m.logical_blocks[t].equiv = LogicalConstraint( expr=m.Y[t, '0'].equivalent_to(lor(m.Y[t_, str(q)] for t_ in range(1, t) for q in range(t - t_, m.T_max - t_ + 1))) ) # Objective function m.objective = Objective(expr=sum(m.alpha[t]*m.s[t]+m.c[t] for t in m.T)) # Global constraints m.demand_satisfaction = Constraint(m.T) for t in m.T: m.demand_satisfaction[t] = m.f[t] >= m.D[t] m.material_balance = Constraint(m.T) for t in m.T: m.material_balance[t]=m.s[t] == (m.s[t-1] if t>1 else 0) + m.x[t] - m.f[t] return m
def build_eight_process_flowsheet(): """Build flowsheet for the 8 process problem.""" m = ConcreteModel(name='DuranEx3 Disjunctive') """Set declarations""" m.streams = RangeSet(2, 25, doc="process streams") m.units = RangeSet(1, 8, doc="process units") """Parameter and initial point declarations""" # FIXED COST INVESTMENT COEFF FOR PROCESS UNITS # Format: process #: cost fixed_cost = {1: 5, 2: 8, 3: 6, 4: 10, 5: 6, 6: 7, 7: 4, 8: 5} CF = m.CF = Param(m.units, initialize=fixed_cost) # VARIABLE COST COEFF FOR PROCESS UNITS - STREAMS # Format: stream #: cost variable_cost = { 3: -10, 5: -15, 9: -40, 19: 25, 21: 35, 25: -35, 17: 80, 14: 15, 10: 15, 2: 1, 4: 1, 18: -65, 20: -60, 22: -80 } CV = m.CV = Param(m.streams, initialize=variable_cost, default=0) # initial point information for stream flows initX = { 2: 2, 3: 1.5, 6: 0.75, 7: 0.5, 8: 0.5, 9: 0.75, 11: 1.5, 12: 1.34, 13: 2, 14: 2.5, 17: 2, 18: 0.75, 19: 2, 20: 1.5, 23: 1.7, 24: 1.5, 25: 0.5 } """Variable declarations""" # FLOWRATES OF PROCESS STREAMS m.flow = Var(m.streams, domain=NonNegativeReals, initialize=initX, bounds=(0, 10)) # OBJECTIVE FUNCTION CONSTANT TERM CONSTANT = m.constant = Param(initialize=122.0) """Constraint definitions""" # INPUT-OUTPUT RELATIONS FOR process units 1 through 8 m.use_unit1 = Disjunct() m.use_unit1.inout1 = Constraint(expr=exp(m.flow[3]) - 1 == m.flow[2]) m.use_unit1.no_unit2_flow1 = Constraint(expr=m.flow[4] == 0) m.use_unit1.no_unit2_flow2 = Constraint(expr=m.flow[5] == 0) m.use_unit2 = Disjunct() m.use_unit2.inout2 = Constraint(expr=exp(m.flow[5] / 1.2) - 1 == m.flow[4]) m.use_unit2.no_unit1_flow1 = Constraint(expr=m.flow[2] == 0) m.use_unit2.no_unit1_flow2 = Constraint(expr=m.flow[3] == 0) m.use_unit3 = Disjunct() m.use_unit3.inout3 = Constraint(expr=1.5 * m.flow[9] + m.flow[10] == m.flow[8]) m.no_unit3 = Disjunct() m.no_unit3.no_unit3_flow1 = Constraint(expr=m.flow[9] == 0) m.no_unit3.flow_pass_through = Constraint(expr=m.flow[10] == m.flow[8]) m.use_unit4 = Disjunct() m.use_unit4.inout4 = Constraint(expr=1.25 * (m.flow[12] + m.flow[14]) == m.flow[13]) m.use_unit4.no_unit5_flow = Constraint(expr=m.flow[15] == 0) m.use_unit5 = Disjunct() m.use_unit5.inout5 = Constraint(expr=m.flow[15] == 2 * m.flow[16]) m.use_unit5.no_unit4_flow1 = Constraint(expr=m.flow[12] == 0) m.use_unit5.no_unit4_flow2 = Constraint(expr=m.flow[14] == 0) m.no_unit4or5 = Disjunct() m.no_unit4or5.no_unit5_flow = Constraint(expr=m.flow[15] == 0) m.no_unit4or5.no_unit4_flow1 = Constraint(expr=m.flow[12] == 0) m.no_unit4or5.no_unit4_flow2 = Constraint(expr=m.flow[14] == 0) m.use_unit6 = Disjunct() m.use_unit6.inout6 = Constraint(expr=exp(m.flow[20] / 1.5) - 1 == m.flow[19]) m.use_unit6.no_unit7_flow1 = Constraint(expr=m.flow[21] == 0) m.use_unit6.no_unit7_flow2 = Constraint(expr=m.flow[22] == 0) m.use_unit7 = Disjunct() m.use_unit7.inout7 = Constraint(expr=exp(m.flow[22]) - 1 == m.flow[21]) m.use_unit7.no_unit6_flow1 = Constraint(expr=m.flow[19] == 0) m.use_unit7.no_unit6_flow2 = Constraint(expr=m.flow[20] == 0) m.no_unit6or7 = Disjunct() m.no_unit6or7.no_unit7_flow1 = Constraint(expr=m.flow[21] == 0) m.no_unit6or7.no_unit7_flow2 = Constraint(expr=m.flow[22] == 0) m.no_unit6or7.no_unit6_flow = Constraint(expr=m.flow[19] == 0) m.no_unit6or7.no_unit6_flow2 = Constraint(expr=m.flow[20] == 0) m.use_unit8 = Disjunct() m.use_unit8.inout8 = Constraint(expr=exp(m.flow[18]) - 1 == m.flow[10] + m.flow[17]) m.no_unit8 = Disjunct() m.no_unit8.no_unit8_flow1 = Constraint(expr=m.flow[10] == 0) m.no_unit8.no_unit8_flow2 = Constraint(expr=m.flow[17] == 0) m.no_unit8.no_unit8_flow3 = Constraint(expr=m.flow[18] == 0) # Mass balance equations m.massbal1 = Constraint(expr=m.flow[13] == m.flow[19] + m.flow[21]) m.massbal2 = Constraint(expr=m.flow[17] == m.flow[9] + m.flow[16] + m.flow[25]) m.massbal3 = Constraint(expr=m.flow[11] == m.flow[12] + m.flow[15]) m.massbal4 = Constraint(expr=m.flow[3] + m.flow[5] == m.flow[6] + m.flow[11]) m.massbal5 = Constraint(expr=m.flow[6] == m.flow[7] + m.flow[8]) m.massbal6 = Constraint(expr=m.flow[23] == m.flow[20] + m.flow[22]) m.massbal7 = Constraint(expr=m.flow[23] == m.flow[14] + m.flow[24]) # process specifications m.specs1 = Constraint(expr=m.flow[10] <= 0.8 * m.flow[17]) m.specs2 = Constraint(expr=m.flow[10] >= 0.4 * m.flow[17]) m.specs3 = Constraint(expr=m.flow[12] <= 5 * m.flow[14]) m.specs4 = Constraint(expr=m.flow[12] >= 2 * m.flow[14]) # pure integer constraints m.use1or2 = Disjunction(expr=[m.use_unit1, m.use_unit2]) m.use4or5maybe = Disjunction( expr=[m.use_unit4, m.use_unit5, m.no_unit4or5]) m.use4or5 = Constraint( expr=m.use_unit4.indicator_var + m.use_unit5.indicator_var <= 1) m.use6or7maybe = Disjunction( expr=[m.use_unit6, m.use_unit7, m.no_unit6or7]) m.use4implies6or7 = Constraint(expr=m.use_unit6.indicator_var + m.use_unit7.indicator_var - m.use_unit4.indicator_var == 0) m.use3maybe = Disjunction(expr=[m.use_unit3, m.no_unit3]) m.either3ornot = Constraint(expr=m.use_unit3.indicator_var + m.no_unit3.indicator_var == 1) m.use8maybe = Disjunction(expr=[m.use_unit8, m.no_unit8]) m.use3implies8 = Constraint( expr=m.use_unit3.indicator_var - m.use_unit8.indicator_var <= 0) """Profit (objective) function definition""" m.profit = Objective(expr=sum( getattr(m, 'use_unit%s' % (unit, )).indicator_var * CF[unit] for unit in m.units) + sum(m.flow[stream] * CV[stream] for stream in m.streams) + CONSTANT, sense=minimize) """Bound definitions""" # x (flow) upper bounds x_ubs = {3: 2, 5: 2, 9: 2, 10: 1, 14: 1, 17: 2, 19: 2, 21: 2, 25: 3} for i, x_ub in iteritems(x_ubs): m.flow[i].setub(x_ub) # # optimal solution # m.use_unit1.indicator_var = 0 # m.use_unit2.indicator_var = 1 # m.use_unit3.indicator_var = 0 # m.no_unit3.indicator_var = 1 # m.use_unit4.indicator_var = 1 # m.use_unit5.indicator_var = 0 # m.no_unit4or5.indicator_var = 0 # m.use_unit6.indicator_var = 1 # m.use_unit7.indicator_var = 0 # m.no_unit6or7.indicator_var = 0 # m.use_unit8.indicator_var = 1 # m.no_unit8.indicator_var = 0 return m
def create_model(): """Create a :class:`pyomo.environ.AbstracModel` for the diet problem""" m = AbstractModel("diet") #-------------------------- # Sets #-------------------------- m.F = Set(doc="Foods. :math:`\\mathcal{F}`") m.N = Set(doc="Nutrients. :math:`\\mathcal{N}`") #-------------------------- # Parameters #-------------------------- m.cost = Param(m.F, within=pe.NonNegativeReals, doc="""Cost of each food. :math:`c_f \\geq 0`""") m.content = Param(m.F, m.N, within=pe.NonNegativeReals, doc="""Amount of nutrient in each food. :math:`a_{f,n} \\geq 0`""") m.min_intake = Param(m.N, within=pe.NonNegativeReals, default=0.0, doc="""Lower bound on each nutrient. :math:`y^{min}_n`""") m.max_intake = Param(m.N, within=pe.NonNegativeReals, default=infinity, doc="""Upper bound on each nutrient. :math:`y^{max}_n`""") m.volume = Param(m.F, within=pe.PositiveReals, doc="""Volume per serving of food. :math:`v_f`""") m.max_volume = Param(within=pe.PositiveReals, doc="""Maximum volume of food consumed. :math:`v^{max}`""") #-------------------------- # Variables #-------------------------- m.x = Var(m.F, within=pe.NonNegativeIntegers, doc="""Number of servings consumed of each food. :math:`x_f \\geq 0`""") #-------------------------- # Expressions #-------------------------- m.total_volume = Expression(rule=lambda m: pe.summation(m.volume, m.x), doc="""Total volume of food consumed. \n .. math:: v^{tot} = \\sum_{f \\in \\mathcal{F}} v_f \\cdot x_f""") m.intake = Expression(m.N, rule=lambda m, n: sum(m.content[f, n] * m.x[f] for f in m.F), doc="""Total intake of each nutrient. \n .. math:: y_n = \\sum_{f \\in \\mathcal{F}} \\alpha_{f,n} \\cdot x_f""") #-------------------------- # Objective #-------------------------- m.minimize_total_cost = Objective( rule=lambda m: pe.summation(m.cost, m.x), doc="""Minimize the cost of food that is consumed. \n .. math:: \\min_{x} \\sum_{f \\in \\mathcal{F}} c_f \\cdot x_f""") #-------------------------- # Constraints #-------------------------- m.nutrient_limit = Constraint( m.N, rule=lambda m, n: inequality(m.min_intake[n], m.intake[n], m. max_intake[n]), doc="""Enforce upper and lower bounds on intake of each nutrient. \n .. math:: y^{min}_n \\leq y_n \\leq y^{max}_n""") m.volume_limit = Constraint(expr=m.total_volume <= m.max_volume, doc="""Limit the volume of food consumed. \n .. math:: v^{tot} \\leq v^{max}""") return m
def _make_flash_eq(self): def rule_total_mass_balance(b): return b.flow_mol_phase['Liq'] + \ b.flow_mol_phase['Vap'] == b.flow_mol self.total_flow_balance = Constraint(rule=rule_total_mass_balance) def rule_comp_mass_balance(b, i): return b.flow_mol * b.mole_frac_comp[i] == \ b.flow_mol_phase['Liq'] * b.mole_frac_phase_comp['Liq', i] + \ b.flow_mol_phase['Vap'] * b.mole_frac_phase_comp['Vap', i] self.component_flow_balances = Constraint(self._params.component_list, rule=rule_comp_mass_balance) def rule_mole_frac(b): return sum(b.mole_frac_phase_comp['Liq', i] for i in b._params.component_list) -\ sum(b.mole_frac_phase_comp['Vap', i] for i in b._params.component_list) == 0 self.sum_mole_frac = Constraint(rule=rule_mole_frac) if self.config.defined_state is False: # applied at outlet only self.sum_mole_frac_out = \ Constraint(expr=1 == sum(self.mole_frac_comp[i] for i in self._params.component_list)) if self.config.has_phase_equilibrium: # Definition of equilibrium temperature for smooth VLE self._teq = Var(initialize=self.temperature.value, doc='Temperature for calculating ' 'phase equilibrium') self._t1 = Var(initialize=self.temperature.value, doc='Intermediate temperature for calculating Teq') self.eps_1 = Param(default=0.01, mutable=True, doc='Smoothing parameter for Teq') self.eps_2 = Param(default=0.0005, mutable=True, doc='Smoothing parameter for Teq') # PSE paper Eqn 13 def rule_t1(b): return b._t1 == 0.5 * \ (b.temperature + b.temperature_bubble + sqrt((b.temperature - b.temperature_bubble)**2 + b.eps_1**2)) self._t1_constraint = Constraint(rule=rule_t1) # PSE paper Eqn 14 # TODO : Add option for supercritical extension def rule_teq(b): return b._teq == 0.5 * (b._t1 + b.temperature_dew - sqrt( (b._t1 - b.temperature_dew)**2 + b.eps_2**2)) self._teq_constraint = Constraint(rule=rule_teq) def rule_tr_eq(b, i): return b._teq / b._params.temperature_crit[i] self._tr_eq = Expression(self._params.component_list, rule=rule_tr_eq, doc='Component reduced temperatures [-]') def rule_equilibrium(b, i): return b.fug_vap[i] == b.fug_liq[i] self.equilibrium_constraint = \ Constraint(self._params.component_list, rule=rule_equilibrium)
def test_clonedModel_soln(self): m_orig = fc.create_model() fc.initialize_model(m_orig, 100) m_orig.perturbed_a = Param(initialize=-0.25) m_orig.perturbed_H = Param(initialize=0.55) m_sipopt = sensitivity_calculation( 'sipopt', m_orig, [m_orig.a, m_orig.H], [m_orig.perturbed_a, m_orig.perturbed_H], cloneModel=True) # verify cloned model has _SENSITIVITY_TOOLBOX_DATA block # and original model is untouched self.assertFalse(m_sipopt == m_orig) self.assertTrue( hasattr(m_sipopt, '_SENSITIVITY_TOOLBOX_DATA') and m_sipopt._SENSITIVITY_TOOLBOX_DATA.ctype is Block) self.assertFalse(hasattr(m_orig, '_SENSITIVITY_TOOLBOX_DATA')) self.assertFalse(hasattr(m_orig, 'b')) # verify variable declaration self.assertTrue( hasattr(m_sipopt._SENSITIVITY_TOOLBOX_DATA, 'a') and m_sipopt._SENSITIVITY_TOOLBOX_DATA.a.ctype is Var) self.assertTrue( hasattr(m_sipopt._SENSITIVITY_TOOLBOX_DATA, 'H') and m_sipopt._SENSITIVITY_TOOLBOX_DATA.H.ctype is Var) # verify suffixes self.assertTrue( hasattr(m_sipopt, 'sens_state_0') and m_sipopt.sens_state_0.ctype is Suffix and m_sipopt.sens_state_0[m_sipopt._SENSITIVITY_TOOLBOX_DATA.H] == 2 and m_sipopt.sens_state_0[m_sipopt._SENSITIVITY_TOOLBOX_DATA.a] == 1) self.assertTrue( hasattr(m_sipopt, 'sens_state_1') and m_sipopt.sens_state_1.ctype is Suffix and m_sipopt.sens_state_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.H] == 2 and m_sipopt.sens_state_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.a] == 1) self.assertTrue( hasattr(m_sipopt, 'sens_state_value_1') and m_sipopt.sens_state_value_1.ctype is Suffix and m_sipopt.sens_state_value_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.H] == 0.55 and m_sipopt.sens_state_value_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.a] == -0.25) self.assertTrue( hasattr(m_sipopt, 'sens_init_constr') and m_sipopt.sens_init_constr.ctype is Suffix and m_sipopt.sens_init_constr[ m_sipopt._SENSITIVITY_TOOLBOX_DATA.paramConst[1]] == 1 and m_sipopt.sens_init_constr[ m_sipopt._SENSITIVITY_TOOLBOX_DATA.paramConst[2]] == 2) self.assertTrue( hasattr(m_sipopt, 'sens_sol_state_1') and m_sipopt.sens_sol_state_1.ctype is Suffix) self.assertAlmostEqual(m_sipopt.sens_sol_state_1[m_sipopt.F[15]], -0.00102016765, 8) # These tests require way too much precision for something that # just needs to enforce that bounds are not active... self.assertTrue( hasattr(m_sipopt, 'sens_sol_state_1_z_L') and m_sipopt.sens_sol_state_1_z_L.ctype is Suffix) self.assertAlmostEqual(m_sipopt.sens_sol_state_1_z_L[m_sipopt.u[15]], -2.181712e-09, 13) self.assertTrue( hasattr(m_sipopt, 'sens_sol_state_1_z_U') and m_sipopt.sens_sol_state_1_z_U.ctype is Suffix) self.assertAlmostEqual(m_sipopt.sens_sol_state_1_z_U[m_sipopt.u[15]], 6.580899e-09, 13) # verify deactivated constraints for cloned model self.assertFalse(m_sipopt.FDiffCon[0].active and m_sipopt.FDiffCon[7.5].active and m_sipopt.FDiffCon[15].active) self.assertFalse(m_sipopt.x_dot[0].active and m_sipopt.x_dot[7.5].active and m_sipopt.x_dot[15].active) # verify constraints on original model are still active self.assertTrue(m_orig.FDiffCon[0].active and m_orig.FDiffCon[7.5].active and m_orig.FDiffCon[15].active) self.assertTrue(m_orig.x_dot[0].active and m_orig.x_dot[7.5].active and m_orig.x_dot[15].active) # verify solution # NOTE: This is the solution to the original problem, # not the result of any sensitivity update. self.assertAlmostEqual(value(m_sipopt.J), 0.0048956783, 8)
def build(self): # Call UnitModel.build to setup dynamics super().build() self.scaling_factor = Suffix(direction=Suffix.EXPORT) if (len(self.config.property_package.phase_list) > 1 or 'Liq' not in [p for p in self.config.property_package.phase_list]): raise ConfigurationError( "NF model only supports one liquid phase ['Liq']," "the property package has specified the following phases {}" .format([p for p in self.config.property_package.phase_list])) units_meta = self.config.property_package.get_metadata().get_derived_units # TODO: update IDAES such that solvent and solute lists are automatically created on the parameter block self.solvent_list = Set() self.solute_list = Set() for c in self.config.property_package.component_list: comp = self.config.property_package.get_component(c) try: if comp.is_solvent(): self.solvent_list.add(c) if comp.is_solute(): self.solute_list.add(c) except TypeError: raise ConfigurationError("NF model only supports one solvent and one or more solutes," "the provided property package has specified a component '{}' " "that is not a solvent or solute".format(c)) if len(self.solvent_list) > 1: raise ConfigurationError("NF model only supports one solvent component," "the provided property package has specified {} solvent components" .format(len(self.solvent_list))) # Add unit parameters self.A_comp = Var( self.flowsheet().config.time, self.solvent_list, initialize=1e-12, bounds=(1e-18, 1e-6), domain=NonNegativeReals, units=units_meta('length')*units_meta('pressure')**-1*units_meta('time')**-1, doc='Solvent permeability coeff.') self.B_comp = Var( self.flowsheet().config.time, self.solute_list, initialize=1e-8, bounds=(1e-11, 1e-5), domain=NonNegativeReals, units=units_meta('length')*units_meta('time')**-1, doc='Solute permeability coeff.') self.sigma = Var( self.flowsheet().config.time, initialize=0.5, bounds=(1e-8, 1e6), domain=NonNegativeReals, units=pyunits.dimensionless, doc='Reflection coefficient') self.dens_solvent = Param( initialize=1000, units=units_meta('mass')*units_meta('length')**-3, doc='Pure water density') # Add unit variables self.flux_mass_phase_comp_in = Var( self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, initialize=1e-3, bounds=(1e-12, 1e6), units=units_meta('mass')*units_meta('length')**-2*units_meta('time')**-1, doc='Flux at feed inlet') self.flux_mass_phase_comp_out = Var( self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, initialize=1e-3, bounds=(1e-12, 1e6), units=units_meta('mass')*units_meta('length')**-2*units_meta('time')**-1, doc='Flux at feed outlet') self.avg_conc_mass_phase_comp_in = Var( self.flowsheet().config.time, self.config.property_package.phase_list, self.solute_list, initialize=1e-3, bounds=(1e-8, 1e6), domain=NonNegativeReals, units=units_meta('mass')*units_meta('length')**-3, doc='Average solute concentration at feed inlet') self.avg_conc_mass_phase_comp_out = Var( self.flowsheet().config.time, self.config.property_package.phase_list, self.solute_list, initialize=1e-3, bounds=(1e-8, 1e6), domain=NonNegativeReals, units=units_meta('mass')*units_meta('length')**-3, doc='Average solute concentration at feed outlet') self.area = Var( initialize=1, bounds=(1e-8, 1e6), domain=NonNegativeReals, units=units_meta('length') ** 2, doc='Membrane area') # Build control volume for feed side self.feed_side = ControlVolume0DBlock(default={ "dynamic": False, "has_holdup": False, "property_package": self.config.property_package, "property_package_args": self.config.property_package_args}) self.feed_side.add_state_blocks( has_phase_equilibrium=False) self.feed_side.add_material_balances( balance_type=self.config.material_balance_type, has_mass_transfer=True) self.feed_side.add_energy_balances( balance_type=self.config.energy_balance_type, has_enthalpy_transfer=True) self.feed_side.add_momentum_balances( balance_type=self.config.momentum_balance_type, has_pressure_change=self.config.has_pressure_change) # Add permeate block tmp_dict = dict(**self.config.property_package_args) tmp_dict["has_phase_equilibrium"] = False tmp_dict["parameters"] = self.config.property_package tmp_dict["defined_state"] = False # permeate block is not an inlet self.properties_permeate = self.config.property_package.state_block_class( self.flowsheet().config.time, doc="Material properties of permeate", default=tmp_dict) # Add Ports self.add_inlet_port(name='inlet', block=self.feed_side) self.add_outlet_port(name='retentate', block=self.feed_side) self.add_port(name='permeate', block=self.properties_permeate) # References for control volume # pressure change if (self.config.has_pressure_change is True and self.config.momentum_balance_type != 'none'): self.deltaP = Reference(self.feed_side.deltaP) # mass transfer self.mass_transfer_phase_comp = Var( self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, initialize=1, bounds=(1e-8, 1e6), domain=NonNegativeReals, units=units_meta('mass')*units_meta('time')**-1, doc='Mass transfer to permeate') @self.Constraint(self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, doc="Mass transfer term") def eq_mass_transfer_term(self, t, p, j): return self.mass_transfer_phase_comp[t, p, j] == -self.feed_side.mass_transfer_term[t, p, j] # NF performance equations @self.Expression(self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, doc="Average flux expression") def flux_mass_phase_comp_avg(b, t, p, j): return 0.5 * (b.flux_mass_phase_comp_in[t, p, j] + b.flux_mass_phase_comp_out[t, p, j]) @self.Constraint(self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, doc="Permeate production") def eq_permeate_production(b, t, p, j): return (b.properties_permeate[t].get_material_flow_terms(p, j) == b.area * b.flux_mass_phase_comp_avg[t, p, j]) @self.Constraint(self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, doc="Inlet water and salt flux") def eq_flux_in(b, t, p, j): prop_feed = b.feed_side.properties_in[t] prop_perm = b.properties_permeate[t] comp = self.config.property_package.get_component(j) if comp.is_solvent(): return (b.flux_mass_phase_comp_in[t, p, j] == b.A_comp[t, j] * b.dens_solvent * ((prop_feed.pressure - prop_perm.pressure) - b.sigma[t] * (prop_feed.pressure_osm - prop_perm.pressure_osm))) elif comp.is_solute(): return (b.flux_mass_phase_comp_in[t, p, j] == b.B_comp[t, j] * (prop_feed.conc_mass_phase_comp[p, j] - prop_perm.conc_mass_phase_comp[p, j]) + ((1 - b.sigma[t]) * b.flux_mass_phase_comp_in[t, p, j] * 1 / b.dens_solvent * b.avg_conc_mass_phase_comp_in[t, p, j]) ) @self.Constraint(self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, doc="Outlet water and salt flux") def eq_flux_out(b, t, p, j): prop_feed = b.feed_side.properties_out[t] prop_perm = b.properties_permeate[t] comp = self.config.property_package.get_component(j) if comp.is_solvent(): return (b.flux_mass_phase_comp_out[t, p, j] == b.A_comp[t, j] * b.dens_solvent * ((prop_feed.pressure - prop_perm.pressure) - b.sigma[t] * (prop_feed.pressure_osm - prop_perm.pressure_osm))) elif comp.is_solute(): return (b.flux_mass_phase_comp_out[t, p, j] == b.B_comp[t, j] * (prop_feed.conc_mass_phase_comp[p, j] - prop_perm.conc_mass_phase_comp[p, j]) + ((1 - b.sigma[t]) * b.flux_mass_phase_comp_out[t, p, j] * 1 / b.dens_solvent * b.avg_conc_mass_phase_comp_out[t, p, j]) ) # Average concentration # COMMENT: Chen approximation of logarithmic average implemented @self.Constraint(self.flowsheet().config.time, self.config.property_package.phase_list, self.solute_list, doc="Average inlet concentration") def eq_avg_conc_in(b, t, p, j): prop_feed = b.feed_side.properties_in[t] prop_perm = b.properties_permeate[t] return (b.avg_conc_mass_phase_comp_in[t, p, j] == (prop_feed.conc_mass_phase_comp[p, j] * prop_perm.conc_mass_phase_comp[p, j] * (prop_feed.conc_mass_phase_comp[p, j] + prop_perm.conc_mass_phase_comp[p, j])/2)**(1/3)) @self.Constraint(self.flowsheet().config.time, self.config.property_package.phase_list, self.solute_list, doc="Average inlet concentration") def eq_avg_conc_out(b, t, p, j): prop_feed = b.feed_side.properties_out[t] prop_perm = b.properties_permeate[t] return (b.avg_conc_mass_phase_comp_out[t, p, j] == (prop_feed.conc_mass_phase_comp[p, j] * prop_perm.conc_mass_phase_comp[p, j] * (prop_feed.conc_mass_phase_comp[p, j] + prop_perm.conc_mass_phase_comp[p, j])/2)**(1/3)) # Feed and permeate-side connection @self.Constraint(self.flowsheet().config.time, self.config.property_package.phase_list, self.config.property_package.component_list, doc="Mass transfer from feed to permeate") def eq_connect_mass_transfer(b, t, p, j): return (b.properties_permeate[t].get_material_flow_terms(p, j) == -b.feed_side.mass_transfer_term[t, p, j]) @self.Constraint(self.flowsheet().config.time, doc="Enthalpy transfer from feed to permeate") def eq_connect_enthalpy_transfer(b, t): return (b.properties_permeate[t].get_enthalpy_flow_terms('Liq') == -b.feed_side.enthalpy_transfer[t]) @self.Constraint(self.flowsheet().config.time, doc="Isothermal assumption for permeate") def eq_permeate_isothermal(b, t): return b.feed_side.properties_out[t].temperature == \ b.properties_permeate[t].temperature