def load_titer(self, titer): """ Load titer specification Parameters ---------- titer : float Titer for fermentors in g products / L effluent. Notes ----- Substrate concentration in bioreactor feed is adjusted to satisfy this specification. Warnings -------- Changing the titer affects the productivity. """ f = self._titer_objective_function feed = self.feed feed.imol[self.products] = 0. substates = feed.imass[self.substrates].sum() self.titer = titer try: flx.aitken_secant(f, substates, ytol=1e-5) except: flx.IQ_interpolation(f, 1e-12, 0.50 * feed.F_mass, ytol=1e-5, maxiter=100) self.reactor.tau = titer / self.productivity
def solve_payment(payment, loan, interest, years): principal = initial_loan_principal(loan, interest) payment = flx.aitken_secant(final_loan_principal, payment, payment+10., 1., 10., args=(principal, interest, years), maxiter=200, checkiter=False) return payment
def solve_incentive(self): """ Return the required incentive (USD) to reach the break even point (NPV = 0) through cash flow analysis. """ discount_factors = (1 + self.IRR)**self._get_duration_array() sales_coefficients = np.ones_like(discount_factors) start = self._start sales_coefficients[:start] = 0 w0 = self._startup_time sales_coefficients[self._start] = w0 * self.startup_VOCfrac + (1 - w0) sales = self._sales if not sales or np.isnan(sales): sales = 0. taxable_cashflow, nontaxable_cashflow = self._taxable_and_nontaxable_cashflow_arrays( ) args = (taxable_cashflow, nontaxable_cashflow, sales_coefficients, discount_factors) sales = flx.aitken_secant(self._NPV_with_sales, sales, 1.0001 * sales + 1e-4, xtol=1e-6, ytol=10., maxiter=300, args=args, checkiter=False) self._sales = sales return sales
def solve_incentive(self, TEA=None): """ Return the required incentive (USD) to reach the break even point (NPV = 0) through cash flow analysis. Parameters ---------- TEA=None : TEA, optional Incentive will be added using settings from given TEA. Defaults to first TEA object in the `TEAs` attribute. """ IRR = self.IRR if not TEA: TEA = self.TEAs[0] discount_factors = (1. + IRR)**TEA._get_duration_array() sales_coefficients = np.ones_like(discount_factors) start = TEA._start sales_coefficients[:start] = 0 w0 = TEA._startup_time sales_coefficients[TEA._start] = w0 * TEA.startup_VOCfrac + (1 - w0) sales = self._sales if not sales or np.isnan(sales): sales = 0. taxable_cashflow, nontaxable_cashflow = self.taxable_and_nontaxable_cashflow_arrays args = (self.income_tax, taxable_cashflow, nontaxable_cashflow, sales_coefficients, discount_factors) sales = flx.aitken_secant(NPV_with_sales, sales, 1.0001 * sales + 1e-4, xtol=1e-6, ytol=10., maxiter=300, args=args, checkiter=False) self._sales = sales return sales
def Tmax_Lakshmi_Prasad(MW): """ Returns the maximum temperature at which the Lakshmi Prasad method is valid. """ T_max = flx.aitken_secant(Lakshmi_Prasad.function, 298.15, args=(MW, )) return T_max - 10 # As an extra precaution
def solve_price(self, stream): """Return the price (USD/kg) of stream at the break even point (NPV = 0) through cash flow analysis. Parameters ---------- stream : :class:`~thermosteam.Stream` Stream with variable selling price. """ price2cost = self._price2cost(stream) cashflow = self.cashflow discount_factors = (1 + self.IRR)**self._duration_array NPV = (cashflow / discount_factors).sum() coefficients = np.ones_like(discount_factors) start = self._start coefficients[:start] = 0 w0 = self._startup_time coefficients[self._start] = w0 * self.startup_VOCfrac + (1 - w0) args = (NPV, coefficients, discount_factors) sales = self._sales or stream.price * price2cost sales = flx.aitken_secant(NPV_with_sales, sales, 1.0001 * sales + 1e-4, ytol=10., maxiter=200, args=args, checkiter=False) self._sales = sales if stream.sink: return stream.price - sales / price2cost elif stream.source: return stream.price + sales / price2cost else: raise ValueError("stream must be either a feed or a product")
def solve_Px(self, z, T): """ Dew point given composition and temperature. Parameters ---------- z : ndarray Molar composition. T : float Temperature (K). Returns ------- P : float Dew point pressure (Pa). x : ndarray Liquid phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> DP = tmo.equilibrium.DewPoint(chemicals) >>> DP.solve_Px(z=np.array([0.5, 0.5]), T=352.28) (82444.29876, array([0.853, 0.147])) """ z_norm = z / z.sum() Psats = array([i(T) for i in self.Psats], dtype=float) z_over_Psats = z / Psats args = (T, z_norm, z_over_Psats) self.T = T f = self._P_error P_guess = self.P or self._P_ideal(z_over_Psats) try: P = flx.aitken_secant(f, P_guess, P_guess - 10, 1e-3, 5e-12, args, checkiter=False) except (InfeasibleRegion, DomainError): Pmin = self.Pmin Pmax = self.Pmax P = flx.IQ_interpolation(f, Pmin, Pmax, f(Pmin, *args), f(Pmax, *args), P_guess, 1e-3, 5e-12, args, checkiter=False, checkbounds=False) self.x = fn.normalize(self.x) return P, self.x.copy()
def solve_sales(self): """ Return the required additional sales (USD) to reach the breakeven point (NPV = 0) through cash flow analysis. """ discount_factors = (1 + self.IRR)**self._get_duration_array() sales_coefficients = np.ones_like(discount_factors) start = self._start sales_coefficients[:start] = 0 w0 = self._startup_time sales_coefficients[self._start] = w0 * self.startup_VOCfrac + (1 - w0) sales = self._sales if not np.isfinite(sales): sales = 0. taxable_cashflow, nontaxable_cashflow = self._taxable_and_nontaxable_cashflow_arrays( ) args = (taxable_cashflow, nontaxable_cashflow, sales_coefficients, discount_factors, self._fill_tax_and_incentives) x0 = sales x1 = 1.01 * sales + 10 f = NPV_with_sales try: sales = flx.aitken_secant(f, x0, x1, xtol=10, ytol=1000., maxiter=1000, args=args, checkiter=True) except Exception as e: y0 = f(x0, *args) y1 = f(x1, *args) if y0 == y1 and y0 < 0.: x0 = -y1 / self._years else: raise e sales = flx.aitken_secant(f, x0, x1, xtol=10, ytol=1000., maxiter=1000, args=args, checkiter=True) self._sales = sales return sales
def solve_Tx(self, z, P): """ Dew point given composition and pressure. Parameters ---------- z : ndarray Molar composition. P : float Pressure [Pa]. Returns ------- T : float Dew point temperature [K]. x : numpy.ndarray Liquid phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> DP = tmo.equilibrium.DewPoint(chemicals) >>> DP.solve_Tx(z=np.array([0.5, 0.5]), P=101325) (357.451847, array([0.849, 0.151])) """ f = self._T_error z_norm = z / z.sum() zP = z * P args = (P, z_norm, zP) self.P = P T_guess = self.T or self._T_ideal(zP) try: T = flx.aitken_secant(f, T_guess, T_guess + 1e-3, 1e-9, 5e-12, args, checkiter=False) except (InfeasibleRegion, DomainError): Tmin = self.Tmin Tmax = self.Tmax T = flx.IQ_interpolation(f, Tmin, Tmax, f(Tmin, *args), f(Tmax, *args), T_guess, 1e-9, 5e-12, args, checkiter=False, checkbounds=False) self.x = fn.normalize(self.x) return T, self.x.copy()
def _run(self): steam = self.ins[1] steam_mol = steam.F_mol steam_mol = flx.aitken_secant(self.pressure_objective_function, steam_mol, steam_mol + 0.1, 1e-4, 1e-4, checkroot=False)
def solve_IRR(self): """Return the IRR at the break even point (NPV = 0) through cash flow analysis.""" IRR = self._IRR if not IRR or np.isnan(IRR) or IRR < 0.: IRR = self.IRR if not IRR or np.isnan(IRR) or IRR < 0.: IRR = 0.10 args = (self.cashflow_array, self._get_duration_array()) self._IRR = flx.aitken_secant(NPV_at_IRR, IRR, 1.0001 * IRR + 1e-3, xtol=1e-6, ytol=10., maxiter=200, args=args, checkiter=False) return self._IRR
def correct_mass_balance(self, variable=None): """ Make sure mass is not created or destroyed by varying the reactant stoichiometric coefficient. """ if variable: index = self.chemicals.get_index(variable) else: index = self._X_index stoichiometry_by_wt = self._get_stoichiometry_by_wt() def f(x): stoichiometry_by_wt[index] = x return stoichiometry_by_wt.sum() flx.aitken_secant(f, 1) if self._basis == 'mol': self._stoichiometry[:] = stoichiometry_by_wt / self.MWs self._rescale()
def adjust_F402_V(): H2O_molfrac = D404_P.outs[0].get_molar_composition('H2O') V0 = H2O_molfrac F402.V = aitken_secant(f=purity_at_V, x0=V0, x1=V0 + 0.001, xtol=0.001, ytol=0.001, maxiter=50, args=())
def _run(self): feed, steam = self._ins steam_mol = steam.F_mol mixed = self.outs[0] steam_mol = aitken_secant(self._P_at_flow, steam_mol, steam_mol+0.1, 1e-4, 1e-4, args=(self.P, steam, mixed, feed)) mixed.P = self.P hu = self.heat_utilities[0] hu(steam.Hvap, mixed.T)
def solve_IRR(self): """Return the IRR at the break even point (NPV = 0) through cash flow analysis.""" IRR = self._IRR args = (self.cashflow, self._duration_array) IRR = flx.aitken_secant(NPV_at_IRR, IRR, 1.0001 * IRR + 1e-3, xtol=1e-6, ytol=10., maxiter=200, args=args, checkiter=False) self._IRR = IRR return IRR
def solve_IRR(self): """Return the IRR at the break even point (NPV = 0) through cash flow analysis.""" IRR = self._IRR args = (tuple([i.cashflow for i in self.TEAs]), tuple([i._duration_array for i in self.TEAs])) self._IRR = flx.aitken_secant(sum_NPV_at_IRR, IRR, 1.0001 * IRR + 1e-3, xtol=1e-6, ytol=10., maxiter=200, args=args, checkiter=False) return self._IRR
def solve_Py(self, z, T): """ Bubble point at given composition and temperature. Parameters ---------- z : ndarray Molar composotion. T : float Temperature [K]. Returns ------- P : float Bubble point pressure [Pa]. y : ndarray Vapor phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> BP = tmo.equilibrium.BubblePoint(chemicals) >>> BP.solve_Py(z=np.array([0.703, 0.297]), T=352.28) (91830.9798, array([0.419, 0.581])) """ self.T = T Psat = array([i(T) for i in self.Psats]) z_norm = z / z.sum() z_Psat_gamma_pcf = z * Psat * self.gamma(z_norm, T) * self.pcf(z_norm, T) f = self._P_error args = (T, z_Psat_gamma_pcf) P_guess = self.P or self._P_ideal(z_Psat_gamma_pcf) try: P = flx.aitken_secant(f, P_guess, P_guess-1, 1e-3, 1e-9, args, checkiter=False) except (InfeasibleRegion, DomainError): Pmin = self.Pmin; Pmax = self.Pmax P = flx.IQ_interpolation(f, Pmin, Pmax, f(Pmin, *args), f(Pmax, *args), P_guess, 1e-3, 5e-12, args, checkiter=False, checkbounds=False) self.y = fn.normalize(self.y) return P, self.y.copy()
def solve_Ty(self, z, P): """ Bubble point at given composition and pressure. Parameters ---------- z : ndarray Molar composotion. P : float Pressure [Pa]. Returns ------- T : float Bubble point temperature [K]. y : ndarray Vapor phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> BP = tmo.equilibrium.BubblePoint(chemicals) >>> BP.solve_Ty(z=np.array([0.6, 0.4]), P=101325) (353.7543, array([0.381, 0.619])) """ self.P = P f = self._T_error z_norm = z / z.sum() z_over_P = z_norm/P args = (P, z_over_P, z_norm) T_guess = self.T or self._T_ideal(z_over_P) try: T = flx.aitken_secant(f, T_guess, T_guess + 1e-3, 1e-9, 5e-12, args, checkiter=False) except (InfeasibleRegion, DomainError): Tmin = self.Tmin; Tmax = self.Tmax T = flx.IQ_interpolation(f, Tmin, Tmax, f(Tmin, *args), f(Tmax, *args), T_guess, 1e-9, 5e-12, args, checkiter=False, checkbounds=False) self.y = fn.normalize(self.y) return T, self.y.copy()
def _run(self): ins = self._ins steam = ins[1] steam_mol = steam.molnet mixed = self.outs[0] index_water = mixed.index('7732-18-5') steam_mol = aitken_secant(self._P_at_flow, steam_mol, steam_mol + 0.1, 1e-4, 1e-4, args=(self.P, steam.mol, index_water, mixed, ins)) mixed.P = self.P hu = self._heat_utilities[0] hu.ID = 'Low pressure steam' hu.flow = steam_mol hu.cost = steam_mol * bst.HeatUtility.heating_agents[ 'Low pressure steam'].price_kmol
def solve_price(self, stream, TEA=None): """Return the price (USD/kg) of stream at the break even point (NPV = 0) through cash flow analysis. Parameters ---------- stream : :class:`~thermosteam.Stream` Stream with variable selling price. TEA : TEA, optional Stream should belong here. """ TEAs = self.TEAs if not TEA: for TEA in TEAs: if stream in TEA.system.feeds or stream in TEA.system.products: break price2cost = TEA._price2cost(stream) IRR = self.IRR NPV = self.NPV discount_factors = (1. + IRR)**TEA._duration_array coefficients = np.ones_like(discount_factors) start = TEA._start coefficients[:start] = 0 w0 = TEA._startup_time coefficients[TEA._start] = w0 * TEA.startup_VOCfrac + (1 - w0) args = (NPV, coefficients, discount_factors) sales = self._sales or stream.price * price2cost sales = flx.aitken_secant(NPV_with_sales, sales, 1.0001 * sales + 1e-4, ytol=10., maxiter=200, args=args, checkiter=False) self._sales = sales if stream.sink: return stream.price - sales / price2cost elif stream.source: return stream.price + sales / price2cost else: raise ValueError("stream must be either a feed or a product")
def solve_Ty(self, z, P): """ Bubble point at given composition and pressure. Parameters ---------- z : ndarray Molar composition. P : float Pressure [Pa]. Returns ------- T : float Bubble point temperature [K]. y : ndarray Vapor phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> BP = tmo.equilibrium.BubblePoint(chemicals) >>> BP.solve_Ty(z=np.array([0.6, 0.4]), P=101325) (353.7543, array([0.381, 0.619])) """ positives = z > 0. N = positives.sum() if N == 0: raise ValueError('no components present') if N == 1: T = self.chemicals[fn.first_true_index(positives)].Tsat(P) y = z.copy() else: if P > self.Pmax: P = self.Pmax elif P < self.Pmin: P = self.Pmin f = self._T_error z_norm = z / z.sum() z_over_P = z / P T_guess, y = self._Ty_ideal(z_over_P) args = (P, z_over_P, z_norm, y) try: T = flx.aitken_secant(f, T_guess, T_guess + 1e-3, 1e-9, 5e-12, args, checkiter=False) except (InfeasibleRegion, DomainError): Tmin = self.Tmin Tmax = self.Tmax T = flx.IQ_interpolation(f, Tmin, Tmax, f(Tmin, *args), f(Tmax, *args), T_guess, 1e-9, 5e-12, args, checkiter=False, checkbounds=False) return T, fn.normalize(y)
def solve_Tx(self, z, P): """ Dew point given composition and pressure. Parameters ---------- z : ndarray Molar composition. P : float Pressure [Pa]. Returns ------- T : float Dew point temperature [K]. x : numpy.ndarray Liquid phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> DP = tmo.equilibrium.DewPoint(chemicals) >>> DP.solve_Tx(z=np.array([0.5, 0.5]), P=101325) (357.451847, array([0.849, 0.151])) """ positives = z > 0. N = positives.sum() if N == 0: raise ValueError('no positive components present') if N == 1: T = self.chemicals[fn.first_true_index(positives)].Tsat(P) x = z.copy() else: if P > self.Pmax: P = self.Pmax elif P < self.Pmin: P = self.Pmin f = self._T_error z_norm = z / z.sum() zP = z * P T_guess, x = self._Tx_ideal(zP) args = (P, z_norm, zP, x) try: T = flx.aitken_secant(f, T_guess, T_guess + 1e-3, 1e-9, 5e-12, args, checkiter=False) except (InfeasibleRegion, DomainError): Tmin = self.Tmin Tmax = self.Tmax T = flx.IQ_interpolation(f, Tmin, Tmax, f(Tmin, *args), f(Tmax, *args), T_guess, 1e-9, 5e-12, args, checkiter=False, checkbounds=False) return T, fn.normalize(x)
def solve_Px(self, z, T): """ Dew point given composition and temperature. Parameters ---------- z : ndarray Molar composition. T : float Temperature (K). Returns ------- P : float Dew point pressure (Pa). x : ndarray Liquid phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> DP = tmo.equilibrium.DewPoint(chemicals) >>> DP.solve_Px(z=np.array([0.5, 0.5]), T=352.28) (82444.29876, array([0.853, 0.147])) """ positives = z > 0. N = positives.sum() if N == 0: raise ValueError('no positive components present') if N == 1: P = self.chemicals[fn.first_true_index(z)].Psat(T) x = z.copy() else: if T > self.Tmax: T = self.Tmax elif T < self.Tmin: T = self.Tmin z_norm = z / z.sum() Psats = np.array([i(T) for i in self.Psats], dtype=float) z_over_Psats = z / Psats P_guess, x = self._Px_ideal(z_over_Psats) args = (T, z_norm, z_over_Psats, x) f = self._P_error try: P = flx.aitken_secant(f, P_guess, P_guess - 10, 1e-3, 5e-12, args, checkiter=False) except (InfeasibleRegion, DomainError): Pmin = self.Pmin Pmax = self.Pmax P = flx.IQ_interpolation(f, Pmin, Pmax, f(Pmin, *args), f(Pmax, *args), P_guess, 1e-3, 5e-12, args, checkiter=False, checkbounds=False) return P, fn.normalize(x)
x0, x1 = [-5, 5] f = lambda x: x**3 - 40 + 2*x p = flx.Profiler(f) x_brentq = opt.brentq(p, x0, x1, xtol=1e-8) p.archive('[Scipy] Brent-Q') # Save/archive results with given name x_brenth = opt.brenth(p, x0, x1) p.archive('[Scipy] Brent-H') x_IQ = flx.IQ_interpolation(p, x0, x1) p.archive('IQ-interpolation') x_false_position = flx.false_position(p, x0, x1) p.archive('False position') p.plot(r'$f(x) = 0 = x^3 + 2 \cdot x - 40$ where $-5 < x < 5$') p = flx.Profiler(f) x_guess = -5 x_aitken_secant = flx.aitken_secant(p, x_guess) p.archive('Aitken') x_secant = flx.secant(p, x_guess) p.archive('Secant') x_newton = opt.newton(p, x_guess) p.archive('[Scipy] Newton') p.plot(r'$f(x) = 0 = x^3 + 2 \cdot x - 40$') # Note that x = 40/x^2 - 2/x is the same # objective function as x**3 - 40 + 2*x = 0 f = lambda x: 40/x**2 - 2/x p = flx.Profiler(f) x_guess = 5. x_wegstein = flx.wegstein(p, x_guess) p.archive('Wegstein') x_aitken = flx.aitken(p, x_guess)
def solve_Py(self, z, T): """ Bubble point at given composition and temperature. Parameters ---------- z : ndarray Molar composition. T : float Temperature [K]. Returns ------- P : float Bubble point pressure [Pa]. y : ndarray Vapor phase molar composition. Examples -------- >>> import thermosteam as tmo >>> import numpy as np >>> chemicals = tmo.Chemicals(['Water', 'Ethanol'], cache=True) >>> tmo.settings.set_thermo(chemicals) >>> BP = tmo.equilibrium.BubblePoint(chemicals) >>> BP.solve_Py(z=np.array([0.703, 0.297]), T=352.28) (91830.9798, array([0.419, 0.581])) """ positives = z > 0. N = positives.sum() if N == 0: raise ValueError('no components present') if N == 1: P = self.chemicals[fn.first_true_index(positives)].Psat(T) y = z.copy() else: if T > self.Tmax: T = self.Tmax elif T < self.Tmin: T = self.Tmin Psat = np.array([i(T) for i in self.Psats]) z_norm = z / z.sum() z_Psat_gamma_pcf = z * Psat * self.gamma(z_norm, T) * self.pcf( z_norm, T) f = self._P_error P_guess, y = self._Py_ideal(z_Psat_gamma_pcf) args = (T, z_Psat_gamma_pcf, y) try: P = flx.aitken_secant(f, P_guess, P_guess - 1, 1e-3, 1e-9, args, checkiter=False) except (InfeasibleRegion, DomainError): Pmin = self.Pmin Pmax = self.Pmax P = flx.IQ_interpolation(f, Pmin, Pmax, f(Pmin, *args), f(Pmax, *args), P_guess, 1e-3, 5e-12, args, checkiter=False, checkbounds=False) return P, fn.normalize(y)