Esempio n. 1
0
    def compute_err(self, svals, dvals, tol_type):
        """Compute the diff between svals and dvals for the given tol_type"""
        if tol_type not in ("abs", "rel"):
            raise ValueError("Invalid tol_type '%s'" % (tol_type, ))

        diff = svals - dvals
        if tol_type == "abs":
            err = diff
        else:
            # relative: divide by current value of svals
            old_settings = numpy.seterr(divide='ignore', invalid='ignore')
            err = diff / svals
            numpy.seterr(**old_settings)
            # isnan means 0/0 so diff is 0
            err[numpy.isnan(err)] = 0
            # isinf means diff/0, so just use the diff
            if any(numpy.isinf(err)):
                for i in range(len(err)):
                    if numpy.isinf(err[i]):
                        err[i] = diff[i]

        return err
Esempio n. 2
0
    def solve_tear_wegstein(self, G, order, function, tears, outEdges, iterLim,
                            tol, tol_type, report_diffs, accel_min, accel_max):
        """
        Use Wegstein to solve tears. If multiple tears are given
        they are solved simultaneously.

        Arguments
        ---------
            order
                List of lists of order in which to calculate nodes
            tears
                List of tear edge indexes
            iterLim
                Limit on the number of iterations to run
            tol
                Tolerance at which iteration can be stopped
            accel_min
                Minimum value for Wegstein acceleration factor
            accel_max
                Maximum value for Wegstein acceleration factor
            tol_type
                Type of tolerance value, either "abs" (absolute) or
                "rel" (relative to current value)

        Returns
        -------
            list
                List of lists of diff history, differences between input and
                output values at each iteration
        """
        hist = []  # diff at each iteration in every variable

        if not len(tears):
            # no need to iterate just run the calculations
            self.run_order(G, order, function, tears)
            return hist

        logger.info("Starting Wegstein tear convergence")

        itercount = 0
        ignore = tears + outEdges

        gofx = self.generate_gofx(G, tears)
        x = self.generate_first_x(G, tears)

        err = self.compute_err(gofx, x, tol_type)
        hist.append(err)

        if report_diffs:
            print("Diff matrix:\n%s" % err)

        # check if it's already solved
        if numpy.max(numpy.abs(err)) < tol:
            logger.info("Wegstein converged in %s iterations" % itercount)
            return hist

        # if not solved yet do one direct step
        x_prev = x
        gofx_prev = gofx
        x = gofx
        self.pass_tear_wegstein(G, tears, gofx)

        while True:
            itercount += 1

            logger.info("Running Wegstein iteration %s" % itercount)
            self.run_order(G, order, function, ignore)

            gofx = self.generate_gofx(G, tears)

            err = self.compute_err(gofx, x, tol_type)
            hist.append(err)

            if report_diffs:
                print("Diff matrix:\n%s" % err)

            if numpy.max(numpy.abs(err)) < tol:
                break

            if itercount > iterLim:
                logger.warning("Wegstein failed to converge in %s iterations" %
                               iterLim)
                return hist

            denom = x - x_prev
            # this will divide by 0 at some points but we handle that below,
            # so ignore division warnings
            old_settings = numpy.seterr(divide='ignore', invalid='ignore')
            slope = numpy.divide((gofx - gofx_prev), denom)
            numpy.seterr(**old_settings)
            # if isnan or isinf then x and x_prev were the same,
            # so just do direct sub for those elements
            slope[numpy.isnan(slope)] = 0
            slope[numpy.isinf(slope)] = 0
            accel = slope / (slope - 1)
            accel[accel < accel_min] = accel_min
            accel[accel > accel_max] = accel_max
            x_prev = x
            gofx_prev = gofx
            x = accel * x_prev + (1 - accel) * gofx_prev
            self.pass_tear_wegstein(G, tears, x)

        self.pass_edges(G, outEdges)

        logger.info("Wegstein converged in %s iterations" % itercount)

        return hist