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
Esempio n. 10
0
    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