def batch_setting_unit_params(df, model, unit, exclude=()): for para in df.index: if para in exclude: continue b = getattr(unit, para) lower = float(df.loc[para]['low']) upper = float(df.loc[para]['high']) dist = df.loc[para]['distribution'] if dist == 'uniform': D = shape.Uniform(lower=lower, upper=upper) elif dist == 'triangular': D = shape.Triangle(lower=lower, midpoint=b, upper=upper) elif dist == 'constant': continue else: raise ValueError( f'Distribution {dist} not recognized for unit {unit}.') su_type = type(unit).__name__ if su_type.lower() == 'lagoon': su_type = f'{unit.design_type.capitalize()} lagoon' name = f'{su_type} {para}' model.parameter(setter=AttrSetter(unit, para), name=name, element=unit, kind='coupled', units=df.loc[para]['unit'], baseline=b, distribution=D)
def bounded_triang(mid, lb=0, ub=1, proportion=0, addition=0.1): # pragma: no cover if lb > ub: ub, lb = lb, ub lower = (1. - proportion) * mid - addition upper = (1. + proportion) * mid + addition if lower > upper: upper, lower = lower, upper if lower < lb: lower = lb if upper > ub: upper = ub return shape.Triangle(lower, mid, upper)
def test_model_exception_hook(): import biosteam as bst import pytest from biorefineries import lipidcane as lc from chaospy import distributions as shape from warnings import simplefilter import numpy as np bst.settings.set_thermo(lc.chemicals) simplefilter("ignore") IRR_metric = bst.Metric('Internal rate of return', lc.lipidcane_tea.solve_IRR) metrics = [IRR_metric] lipidcane_model = bst.Model(lc.lipidcane_sys, metrics) baseline = lc.lipidcane.F_mass distribution = shape.Triangle(-baseline, baseline, 2 * baseline) # Negative value should fail @lipidcane_model.parameter(element=lc.lipidcane, distribution=distribution, units='kg/hr') def set_lipidcane_flow_rate(flow_rate): lc.lipidcane.F_mass = flow_rate samples = lipidcane_model.sample(15, 'L') lipidcane_model.load_samples(samples) # Without an exception hook, the same behavior will result (NaN values for failed evaluations) lipidcane_model.evaluate() assert np.isnan(lipidcane_model.table.values).any() InfeasibleRegion = bst.exceptions.InfeasibleRegion # This will provide a more understandable IRR result for infeasible regions def exception_hook(exception, sample): if isinstance(exception, (InfeasibleRegion, ValueError, RuntimeError)): return [0] else: raise exception lipidcane_model.exception_hook = exception_hook lipidcane_model.evaluate() assert not np.isnan(lipidcane_model.table.values).any() # This will raise an exception due to negative flow rates def exception_hook(exception, sample): if isinstance(exception, InfeasibleRegion): raise exception lipidcane_model.exception_hook = exception_hook with pytest.raises(InfeasibleRegion): lipidcane_model.evaluate() # This will raise an exception regardless def exception_hook(exception, sample): raise exception lipidcane_model.exception_hook = exception_hook with pytest.raises(InfeasibleRegion): lipidcane_model.evaluate() # Here is another cool thing we could do in the case where # some metrics are expected to fail bad_metric = bst.Metric('bad metric', lambda: 1 / 0) lipidcane_model.metrics = (IRR_metric, bad_metric) lipidcane_model.load_samples( samples) # Metrics changed, so need to reload sample def exception_hook(exception, sample): if not isinstance(exception, ZeroDivisionError): return lc.lipidcane_sys.simulate() values = [] for i in lipidcane_model.metrics: try: x = i() except: x = None values.append(x) return values lipidcane_model.exception_hook = exception_hook lipidcane_model.evaluate() bad_metric_results = lipidcane_model.table[bad_metric.index] IRR_metric_results = lipidcane_model.table[IRR_metric.index] assert np.isnan(bad_metric_results).all() assert not np.isnan(IRR_metric_results).all()
param(setter=Setter(stream, 'price'), name=f'{stream.ID} price', element='TEA', kind='isolated', units='$/kg', baseline=stream.price, distribution=D) for stream_ID in special_price.keys(): stream = getattr(system, stream_ID) lower = special_price[stream_ID][1][0] mid = stream.price upper = special_price[stream_ID][1][-1] if special_price[stream_ID][0] == 'Triangle': D = shape.Triangle(lower, mid, upper) elif special_price[stream.ID][0] == 'Uniform': D = shape.Uniform(lower, upper) add_stream_price_param(stream, D) for stream_ID in default_price_streams: stream = getattr(system, stream_ID) baseline = stream.price D = baseline_uniform(baseline, 0.1) add_stream_price_param(stream, D) D = shape.Triangle(0.067, 0.070, 0.074) @param(name='Electricity price', element='TEA',
def triang(mid, proportion=0.1, addition=0): # pragma: no cover lb = (1. - proportion) * mid - addition ub = (1. + proportion) * mid + addition if lb > ub: ub, lb = lb, ub return shape.Triangle(lb, mid, ub)
def bounded_triang(mid, lb=0, ub=1, proportion=0, addition=0.1): lower = (1. - proportion) * mid - addition upper = (1. + proportion) * mid + addition if lower < lb: lower = lb if upper > ub: upper = ub return shape.Triangle(lower, mid, upper)
def triang(mid, proportion=0.1, addition=0): return shape.Triangle((1. - proportion) * mid - addition, mid, (1. + proportion) * mid + addition)
import biosteam as bst import numpy as np folder = os.path.dirname(__file__) valid_depreciation_schedules = [5, 7, 10, 15, 20] # Should be True for more accurate results, but False for now to speed things up cs._include_blowdown_recycle = False model = bst.Model(cs.cornstover_sys) parameter = model.parameter metric = model.metric @parameter(element=cs.cornstover, distribution=shape.Triangle(105., 83333., 170417.), units='kg/hr') def set_feedstock_flow_rate(flow_rate): cs.cornstover.F_mass = flow_rate @parameter(element=cs.cornstover, distribution=shape.Triangle(0.02, 0.048, 0.111), units='USD/kg') def set_feedstock_price(price): cs.cornstover.price = price @parameter(element='Operation', distribution=shape.Triangle(21, 30, 30), units='year')
# ============================================================================= # model with all uncertain variables # ============================================================================= model_bsm1 = qs.Model(system=bsm1, exception_hook='raise') ########## Add Uncertainty Parameters ########## param = model_bsm1.parameter get_uniform_w_frac = lambda b, frac: shape.Uniform(lower=b * (1 - frac), upper=b * (1 + frac)) cmps = s.cmps PE = s.PE b = 0.08 D = shape.Triangle(lower=0.04, midpoint=b, upper=0.12) @param(name='Biomass N content i_XB', element=PE, kind='coupled', units='g N/g COD', baseline=b, distribution=D) def set_i_XB(i): cmps.X_BH.i_N = cmps.X_BA.i_N = i cmps.refresh_constants() b = 0.06 D = shape.Triangle(lower=0.057, midpoint=b, upper=0.063)
def triang(mid, proportion=0.1, addition=0): # pragma: no cover return shape.Triangle((1. - proportion) * mid - addition, mid, (1. + proportion) * mid + addition)