def SEQ(self, GUESS): self.logger.debug("SEQ reactor called") GUESS = GUESS.F # generate remaining guesses based on guess X_guess = GUESS/sum(GUESS) DATA = np.concatenate((GUESS, X_guess)) # calculate solution based on default solvers for units, then decompose solution solution, stats = Solvers().solve(system = self.System, jacobian = self.Jacobian, guess = DATA, category = 'Unit') Basics().TrackPerformance(stats, 'Unit') solution_flows = solution[0:6] self.logger.info("Converged unit in "+str(stats["Iterations"])+" iterations.") # construct solution stream leaving the reactor and return it FEFF = Stream() FEFF.F = solution_flows FEFF.T = self._TEMPERATURE + self.DrH/(FEFF.Ftotal*CP_reactor)*(self._FEED_A.F[0]+self._FEED_B.F[0]+self._RECYCLE.F[0]-FEFF.F[0]) Basics().mass_balance_check([self._FEED_A, self._FEED_B, self._RECYCLE], [FEFF], by_species = False) return FEFF
def SEQ(self, OUTFLOW_GUESS, WASTE_GUESS): self.logger.debug("SEQ decanter called") OUTFLOW_GUESS = OUTFLOW_GUESS.F WASTE_GUESS = WASTE_GUESS.F # compile guesses DATA = np.concatenate((OUTFLOW_GUESS, WASTE_GUESS)) # calculate solution based on default solvers for units, then decompose solution solution, stats = Solvers().solve(system = self.System, jacobian = self.Jacobian, guess = DATA, category = 'Unit') Basics().TrackPerformance(stats, 'Unit') solution_waste_flows = solution[6:12] solution_outlet_flows = solution[0:6] self.logger.info("Converged unit in "+str(stats["Iterations"])+" iterations.") WASTE = Stream() OUTFLOW = Stream() WASTE.F = solution_waste_flows OUTFLOW.F = solution_outlet_flows WASTE.T = self._TEMPERATURE OUTFLOW.T = self._TEMPERATURE Basics().mass_balance_check([self._FEED], [WASTE, OUTFLOW]) return OUTFLOW, WASTE
def print_Solution(self): print("\n\n") print( "#################################\nSOLUTION (streams in lb/hr)\n#################################\n" ) print(Basics().np_to_pd([ np.concatenate((self._FEED_A.F, np.array([self._FEED_A.T]), np.array([self._FEED_A.Ftotal]))), np.concatenate((self._FEED_B.F, np.array([self._FEED_B.T]), np.array([self._FEED_B.Ftotal]))), np.concatenate((self._REACOUT.F, np.array([self._REACOUT.T]), np.array([self._REACOUT.Ftotal]))), np.concatenate((self._HEATEXOUT.F, np.array([self._HEATEXOUT.T]), np.array([self._HEATEXOUT.Ftotal]))), np.concatenate( (self._DECANTEROUT.F, np.array([self._DECANTEROUT.T]), np.array([self._DECANTEROUT.Ftotal]))), np.concatenate((self._WASTE.F, np.array([self._WASTE.T]), np.array([self._WASTE.Ftotal]))), np.concatenate((self._PRODUCT.F, np.array([self._PRODUCT.T]), np.array([self._PRODUCT.Ftotal]))), np.concatenate((self._BOTTOMS.F, np.array([self._BOTTOMS.T]), np.array([self._BOTTOMS.Ftotal]))), np.concatenate((self._RECYCLE.F, np.array([self._RECYCLE.T]), np.array([self._RECYCLE.Ftotal]))), np.concatenate((self._PURGE.F, np.array([self._PURGE.T]), np.array([self._PURGE.Ftotal]))) ]).to_string(float_format="%0.2f")) print("") print("PURGE RATIO: %1.4f" % self._PURGERATIO) print("\n\n") print("TEMPERATURE AFTER REACTOR: %1.1f" % self._REACOUT.T) print("\n\n") iterations = Basics().getPerformanceAssessment() print( "#################################\nSTATISTICS\n#################################\n" ) for category in iterations: if iterations[category] is not None: print("ITERATIONS %s:\t%1.0f" % (category, iterations[category])) print("\n")
def SEQ(self): self.logger.debug("SEQ splitter called") FA = self._FEED.F[0]; FB = self._FEED.F[1]; FC = self._FEED.F[2]; FE = self._FEED.F[3]; FP = self._FEED.F[4]; FG = self._FEED.F[5]; recycle_flows = np.array([ (1-self._PURGERATIO)*FA, (1-self._PURGERATIO)*FB, (1-self._PURGERATIO)*FC, (1-self._PURGERATIO)*FE, (1-self._PURGERATIO)*FP, 0 ]) purge_flows = self._FEED.F - recycle_flows RECYCLE = Stream() PURGE = Stream() RECYCLE.F = recycle_flows PURGE.F = purge_flows RECYCLE.T = self._TEMPERATURE PURGE.T = self._TEMPERATURE Basics().mass_balance_check([self._FEED], [RECYCLE, PURGE]) return RECYCLE, PURGE
def SEQ(self): self.logger.debug("SEQ distillation called") FA = self._FEED.F[0]; FB = self._FEED.F[1]; FC = self._FEED.F[2]; FE = self._FEED.F[3]; FP = self._FEED.F[4]; FG = self._FEED.F[5]; head_flows = np.array([ 1, 1000/FA, 10*FC/(FC+FE), 50*FE/(FE+FP), max(FP-0.05*FE, 0), FG/(FP+FG) ]) bottom_flows = self._FEED.F - head_flows HEAD = Stream() BOTTOM = Stream() HEAD.F = head_flows BOTTOM.F = bottom_flows HEAD.T = self._TEMPERATURE + 0.5*(800 - self._TEMPERATURE) BOTTOM.T = self._TEMPERATURE - 0.5*(self._TEMPERATURE - 500) Basics().mass_balance_check([self._FEED], [HEAD, BOTTOM]) return HEAD, BOTTOM
def ArmijoLineSearch(self, system, jacobian, guess): if system is None or jacobian is None or guess is None: self.logger.error( "Armijo line search solver incorrectly initialised. It needs the system, the jacobian and a guess." ) raise Exception("Solver incorrectly initialised.") iterations = 0 h = lambda x: 0.5 * np.dot(system(x), system(x)) while iterations < self.max_iterations: iterations = iterations + 1 self.logger.debug("Performing armijo line search iteration #" + str(iterations)) f = system(guess) j = jacobian(guess) j_inv = Basics().inverse(j) step = -np.dot(j_inv, f) a = 1 h_new = h(guess + a * step) h_old = h(guess) while h_new - h_old > -2 * self.armijo_gamma * a * h_old and a > self.armijo_amin: a_q = a * h_old / ((2 * a - 1) * h_old + h_new) factor = max(self.armijo_delta, a_q) a = factor * a h_new = h(guess + a * step) guess = guess + a * step e1 = abs(np.dot(f, f)) e2 = abs(np.dot(a * step, a * step)) if e1 < self.armijo_e1 and e2 < self.armijo_e2: self.logger.debug( "Passed convergence test. Returning solution.") break if iterations == self.max_iterations: self.logger.critical("No convergence achieved.") raise Exception("Solver did not converge in " + str(self.max_iterations) + " iterations.") stats = { 'Iterations': iterations, 'ConvergenceError1': e1, 'ConvergenceError2': e2 } self.logger.info("Converged in " + str(iterations) + " iterations.") return guess, stats
def SEQ_Start(self): if not self.initialised: self.logger.error("Flowsheet SEQ was not set up! Call SEQ_Setup.") return None solution, stats = Solvers().solve(system=self.SEQ_System, guess=self._TEARSTREAM.F, category='TearStream') self.logger.debug("Converged tear stream in " + str(stats["Iterations"]) + " iterations.") Basics().TrackPerformance(stats, 'TearStream') self._TEARSTREAM.F = solution if DEBUG: Basics().TrackSuccess() self.print_Solution() return Basics().np_to_pd([ np.concatenate((self._FEED_A.F, np.array([self._FEED_A.T]), np.array([self._FEED_A.Ftotal]))), np.concatenate((self._FEED_B.F, np.array([self._FEED_B.T]), np.array([self._FEED_B.Ftotal]))), np.concatenate((self._REACOUT.F, np.array([self._REACOUT.T]), np.array([self._REACOUT.Ftotal]))), np.concatenate((self._HEATEXOUT.F, np.array([self._HEATEXOUT.T]), np.array([self._HEATEXOUT.Ftotal]))), np.concatenate( (self._DECANTEROUT.F, np.array([self._DECANTEROUT.T]), np.array([self._DECANTEROUT.Ftotal]))), np.concatenate((self._WASTE.F, np.array([self._WASTE.T]), np.array([self._WASTE.Ftotal]))), np.concatenate((self._PRODUCT.F, np.array([self._PRODUCT.T]), np.array([self._PRODUCT.Ftotal]))), np.concatenate((self._BOTTOMS.F, np.array([self._BOTTOMS.T]), np.array([self._BOTTOMS.Ftotal]))), np.concatenate((self._RECYCLE.F, np.array([self._RECYCLE.T]), np.array([self._RECYCLE.Ftotal]))), np.concatenate((self._PURGE.F, np.array([self._PURGE.T]), np.array([self._PURGE.Ftotal]))) ])
def SEQ(self, Temperature): self.logger.debug("SEQ heat exchanger called") OUTFLOW = Stream() OUTFLOW = self._FEED OUTFLOW.T = Temperature Basics().mass_balance_check([self._FEED], [OUTFLOW]) return OUTFLOW
def Newton(self, system, jacobian, guess): if system is None or jacobian is None or guess is None: self.logger.error( "Newton solver incorrectly initialised. It needs the system, the jacobian and a guess." ) raise Exception("Solver incorrectly initialised.") iterations = 0 while iterations < self.max_iterations: iterations = iterations + 1 self.logger.debug("Performing Newton iteration #" + str(iterations)) f = system(guess) j = jacobian(guess) j_inv = Basics().inverse(j) step = -np.dot(j_inv, f) guess = guess + step e1 = abs(np.dot(f, f)) e2 = abs(np.dot(step, step)) if e1 < self.newton_e1 and e2 < self.newton_e2: self.logger.debug( "Passed convergence test. Returning solution.") break if iterations == self.max_iterations: self.logger.critical("No convergence achieved.") raise Exception("Solver did not converge in " + str(self.max_iterations) + " iterations.") stats = { 'Iterations': iterations, 'ConvergenceError1': e1, 'ConvergenceError2': e2 } self.logger.info("Converged in " + str(iterations) + " iterations.") return guess, stats
def Broyden(self, system, guess): if system is None or guess is None: self.logger.error( "Broyden solver incorrectly initialised. It needs the system and a guess." ) raise Exception("Solver incorrectly initialised.") iterations = 0 B = 1e6 * np.identity(guess.size) guess_prev = None f_prev = None B_prev = None while iterations < self.max_iterations: iterations = iterations + 1 self.logger.debug("Performing broyden iteration #" + str(iterations)) f = system(guess) if guess_prev is not None: delta_x = guess - guess_prev delta_f = f - f_prev B = B_prev + np.outer( (delta_f - np.dot(B_prev, delta_x)), delta_x) / np.dot( delta_x, delta_x) guess_prev = guess f_prev = f B_prev = B B_inv = Basics().inverse(B) step = -np.dot(B_inv, f) guess = guess + step e1 = abs(np.dot(f, f)) e2 = abs(np.dot(step, step)) if e1 < self.broyden_e1 and e2 < self.broyden_e2: self.logger.debug( "Passed convergence test. Returning solution.") break if iterations == self.max_iterations: self.logger.critical("No convergence achieved.") raise Exception("Solver did not converge in " + str(self.max_iterations) + " iterations.") stats = { 'Iterations': iterations, 'ConvergenceError1': e1, 'ConvergenceError2': e2 } self.logger.info("Converged in " + str(iterations) + " iterations.") return guess, stats