<commit_before>#include <cstdio>
#include "Observer.hpp"

namespace
{
    void formatAngle(char *str, int const length, double const angleDeg)
    {
        long const angleMilliDeg = std::lround(degrees(angleDeg) * 1000);
        long const degrees = angleMilliDeg / 1000 % 360;
        long const milliDegrees = angleMilliDeg % 1000;

        if (milliDegrees == 0)
        {
            snprintf(str, length, "%2.2li", degrees);
        } else
        {
            snprintf(str, length, "%2.2li-%3.3li", degrees, milliDegrees);
        }
    }
}

// pictures
Pictures::Pictures(std::uint32_t nx, std::uint32_t ny)
    : nx_{ nx }
    , ny_{ ny }
{
    f_ = new double[ nx*ny ]();
    q_ = new double[ nx*ny ]();
    u_ = new double[ nx*ny ]();
}

Pictures::~Pictures()
{
    delete[] f_;
    delete[] q_;
    delete[] u_;
}

Pictures::Pictures(Pictures&& other) noexcept
    : nx_{ other.nx_ }
    , ny_{ other.ny_ }
    , f_{ other.f_ }
    , q_{ other.q_ }
    , u_{ other.u_ }
{
    other.f_ = nullptr;
    other.q_ = nullptr;
    other.u_ = nullptr;
}

Pictures& Pictures::operator=(Pictures&& other) noexcept
{
    std::swap(f_, other.f_);
    std::swap(q_, other.q_);
    std::swap(u_, other.u_);
    nx_ = other.nx_;
    ny_ = other.ny_;
    return *this;
}

// place photon on the images
void Pictures::bin(Photon const& ph, int64_t const xl, int64_t const yl, int64_t const id, double const weight)
{
    // place weighted photon into image location
    if((id == -1 || static_cast<std::uint64_t>(id) == ph.nscat()) && (xl>=0) && (yl >= 0) && ((std::uint32_t)xl < nx_) && ((std::uint32_t)yl < ny_) )
    {
        f_[xl+yl*nx_] += weight * ph.weight() * ph.fi();
        q_[xl+yl*nx_] += weight * ph.weight() * ph.fq();
        u_[xl+yl*nx_] += weight * ph.weight()*ph.fu();
    }
}

void Pictures::normalize(std::uint64_t const numPhotons)
{
    for (std::uint64_t i=0; i!=nx_*ny_; ++i)
    {
        f_[i] /= numPhotons;
        q_[i] /= numPhotons;
        u_[i] /= numPhotons;
    }
}

void Pictures::write(double const phi, double const theta, int const key) const
{
    int const FILENAME_LENGTH{ 40 };
    int const ANGLE_LENGTH{ 10 };

    char fname[FILENAME_LENGTH];
    char phiStr[ANGLE_LENGTH];
    char thetaStr[ANGLE_LENGTH];

    formatAngle(phiStr, ANGLE_LENGTH, phi);
    formatAngle(thetaStr, ANGLE_LENGTH, theta);

    snprintf(fname, FILENAME_LENGTH, "fimage%s_%s_%2.2i.dat", phiStr, thetaStr, key);
    std::ofstream f(fname);
    f.precision(14);

    for (std::uint64_t y=0; y != ny_; ++y)
    {
        for (std::uint64_t x=0; x!=nx_; ++x)
        {
            f << f_[x + y * nx_] << "\t";
        }
        f << "\n";
    }
    f.close();

    snprintf(fname, FILENAME_LENGTH, "qimage%s_%s_%2.2i.dat", phiStr, thetaStr, key);
    std::ofstream q(fname);
    q.precision(14);

    for (std::uint64_t y=0; y != ny_; ++y)
    {
        for (std::uint64_t x=0; x!=nx_; ++x)
        {
            q << q_[x + y * nx_] << "\t";
        }
        q << "\n";
    }
    q.close();

    snprintf(fname, FILENAME_LENGTH, "uimage%s_%s_%2.2i.dat", phiStr, thetaStr, key);
    std::ofstream u(fname);
    u.precision(14);

    for (std::uint64_t y=0; y != ny_; ++y)
    {
        for (std::uint64_t x=0; x!=nx_; ++x)
        {
            u << u_[x + y * nx_] << "\t";
        }
        u << "\n";
    }
    u.close();
}

void Pictures::sum(std::ofstream& file)
{
    double fsum=0, qsum=0, usum=0;
    for (std::uint64_t x=0; x!=nx_; ++x)
    {
        for (std::uint64_t y=0; y != ny_; ++y)
        {
            fsum += f_[y + x * ny_];
            qsum += q_[y + x * ny_];
            usum += u_[y + x * ny_];
        }
    }
    file << "\tF= " << fsum << "\tQ= " << qsum << "\tU= " << usum
         << "\tp= " << std::sqrt(qsum*qsum + usum*usum)/fsum
         << "\tphi= " << 90 * std::atan2(usum, qsum)/PI;
}

Observer::Observer(double const phi, double const theta, double const rimage, std::uint32_t const Nx, std::uint32_t const Ny)
    : result_(Nx, Ny)
    , result0_(Nx, Ny)
    , result1_(Nx, Ny)
    , result2_(Nx, Ny)
    , direction_{phi, theta}
    , nx_(Nx)
    , ny_(Ny)
{
    rimage_ = rimage;
    theta_ = theta;

    cosp_ = std::cos(phi);
    sinp_ = std::sin(phi);
}

void Observer::normalize(std::uint64_t const numPhotons)
{
    result_.normalize(numPhotons);
    result0_.normalize(numPhotons);
    result1_.normalize(numPhotons);
    result2_.normalize(numPhotons);
}

void Observer::writeToMapFiles(bool const fWriteSingleAndDoubleScatterings)
{
    result_.write(direction_.phi(), theta_, 0);

    if (fWriteSingleAndDoubleScatterings)
    {
        result1_.write(direction_.phi(), theta_, 1);
        result2_.write(direction_.phi(), theta_, 2);
    }
}

void Observer::write(std::ofstream& file)
{
    file << "phi= " << degrees(direction_.phi()) << "\ttheta= " << degrees(theta_);
    result_.sum(file);
    result0_.sum(file);
    result1_.sum(file);
    result2_.sum(file);
    file << "\n";
}

bool Observer::inFov(const Photon &photon) const
{
    double const yimage = rimage_ + photon.pos().z() * direction_.sinTheta() -
                          direction_.cosTheta() * (photon.pos().y()*sinp_ + photon.pos().x()*cosp_);

    double const ximage = rimage_ + photon.pos().y()*cosp_ - photon.pos().x()*sinp_;

    auto const xl = static_cast<int64_t>(nx_ * ximage / (2.0 * rimage_));
    auto const yl = static_cast<int64_t>(ny_ * yimage / (2.0 * rimage_));

    return (xl>=0) && (yl >= 0) && ((std::uint32_t)xl < nx_) && ((std::uint32_t)yl < ny_);
}

void Observer::bin(Photon const& photon)
{
    double const yimage = imageY(photon.pos());
    double const ximage = imageX(photon.pos());

    auto const xl = static_cast<int64_t>(nx_ * ximage / (2.0 * rimage_));
    auto const yl = static_cast<int64_t>(ny_ * yimage / (2.0 * rimage_));

    double const eps = std::numeric_limits<float>::epsilon();

    bin(
        photon,
        xl,
        yl,
        std::abs(ximage - xl * (2.0 * rimage_) / nx_) < eps,
        std::abs(yimage - yl * (2.0 * rimage_) / ny_) < eps,
        1.0);
}

// TODO: Add tests for this method
void Observer::bin(Photon const& photon, const Vector3d &pos1, const Vector3d &pos2)
{
    double const yimage1 = imageY(pos1);
    double const ximage1 = imageX(pos1);
    auto const xl1 = static_cast<int64_t>(nx_ * ximage1 / (2.0 * rimage_));
    auto const yl1 = static_cast<int64_t>(ny_ * yimage1 / (2.0 * rimage_));

    double const yimage2 = imageY(pos2);
    double const ximage2 = imageX(pos2);
    auto const xl2 = static_cast<int64_t>(nx_ * ximage2 / (2.0 * rimage_));
    auto const yl2 = static_cast<int64_t>(ny_ * yimage2 / (2.0 * rimage_));

    double const eps = std::numeric_limits<float>::epsilon();

    if (xl1 == xl2 && yl1 == yl2)
    {
        bin(
            photon,
            xl2,
            yl2,
            std::abs(ximage2 - ximage1) < eps && std::abs(ximage2 - xl2 * (2.0 * rimage_) / nx_) < eps,
            std::abs(yimage2 - yimage1) < eps && std::abs(yimage2 - yl2 * (2.0 * rimage_) / ny_) < eps,
            1.0);

        return;
    }

    double xImageMin = std::min(ximage1, ximage2);
    double xImageMax = std::max(ximage1, ximage2);
    int64_t borderX = xl1;
    int64_t lastBorderX = xl2;

    if (ximage1 > ximage2)
    {
        xImageMin = ximage2;
        xImageMax = ximage1;
        borderX = xl2;
        lastBorderX = xl1;
    }

    double yImageMin = yimage1;
    double yImageMax = yimage2;
    int64_t borderY = yl1;
    int64_t lastBorderY = yl2;

    if (yimage1 > yimage2)
    {
        yImageMin = yimage2;
        yImageMax = yimage1;
        borderY = yl2;
        lastBorderY = yl1;
    }

    double const dx = xImageMax - xImageMin;
    double const dy = yImageMax - yImageMin;
    double const totalW = std::sqrt(dx*dx + dy*dy);

    double x = xImageMin;
    double y = yImageMin;

    while (borderX <= lastBorderX && borderY <= lastBorderY)
    {
        double const xborder = std::min(static_cast<double>(borderX+1) * (2.0 * rimage_) / nx_, xImageMax);
        double const yborder = std::min(static_cast<double>(borderY+1) * (2.0 * rimage_) / ny_, yImageMax);

        double const xt = dx > 0 ? (xborder - x) / dx : std::numeric_limits<double>::infinity();
        double const yt = dy > 0 ? (yborder - y) / dy : std::numeric_limits<double>::infinity();

        if (xt < yt)
        {
            double yNew = y + xt * dy;
            double w = std::sqrt((yNew - y)*(yNew-y) + (xborder - x)*(xborder - x));

            bin(
                photon,
                borderX,
                borderY,
                false,
                dy < eps && std::fabs(y - borderY * (2.0 * rimage_) / ny_) < eps,
                w / totalW);

            ++borderX;
            x = xborder;
            y = yNew;
        } else {
            double xNew = x + yt * dx;
            double w = std::sqrt((xNew - x)*(xNew-x) + (yborder - y)*(yborder - y));

            bin(
                photon,
                borderX,
                borderY,
                dx < eps && std::fabs(x - borderX * (2.0 * rimage_) / nx_) < eps,
                false,
                w / totalW);

            ++borderY;
            x = xNew;
            y = yborder;
        }
    }
}

inline double Observer::imageX(Vector3d const &position) const
{
    return rimage_ + position.y() * cosp_ - position.x() * sinp_;
}

inline double Observer::imageY(Vector3d const &position) const
{
    return rimage_ + position.z() * direction_.sinTheta() - direction_.cosTheta() * (position.y()*sinp_ + position.x()*cosp_);
}

inline void Observer::bin(Photon const& photon, int64_t const x, int64_t const y, double const weight)
{
    result_.bin(photon, x, y, -1, weight);
    result0_.bin(photon, x, y, 0, weight);
    result1_.bin(photon, x, y, 1, weight);
    result2_.bin(photon, x, y, 2, weight);
}

inline void Observer::bin(const Photon &photon, int64_t const x, int64_t const y, bool const onXBorder, bool const onYBorder, double const weight)
{
    if (onXBorder && x > 0)
    {
        bin(photon, x, y, 0.5 * weight);
        bin(photon, x-1, y, 0.5 * weight);
    } else if (onYBorder && y > 0) {
        bin(photon, x, y, 0.5 * weight);
        bin(photon, x, y-1, 0.5 * weight);
    } else {
        bin(photon, x, y, weight);
    }
}
<commit_msg>Bin direct photons to one pixel<commit_after>#include <cstdio>
#include "Observer.hpp"

namespace
{
    void formatAngle(char *str, int const length, double const angleDeg)
    {
        long const angleMilliDeg = std::lround(degrees(angleDeg) * 1000);
        long const degrees = angleMilliDeg / 1000 % 360;
        long const milliDegrees = angleMilliDeg % 1000;

        if (milliDegrees == 0)
        {
            snprintf(str, length, "%2.2li", degrees);
        } else
        {
            snprintf(str, length, "%2.2li-%3.3li", degrees, milliDegrees);
        }
    }
}

// pictures
Pictures::Pictures(std::uint32_t nx, std::uint32_t ny)
    : nx_{ nx }
    , ny_{ ny }
{
    f_ = new double[ nx*ny ]();
    q_ = new double[ nx*ny ]();
    u_ = new double[ nx*ny ]();
}

Pictures::~Pictures()
{
    delete[] f_;
    delete[] q_;
    delete[] u_;
}

Pictures::Pictures(Pictures&& other) noexcept
    : nx_{ other.nx_ }
    , ny_{ other.ny_ }
    , f_{ other.f_ }
    , q_{ other.q_ }
    , u_{ other.u_ }
{
    other.f_ = nullptr;
    other.q_ = nullptr;
    other.u_ = nullptr;
}

Pictures& Pictures::operator=(Pictures&& other) noexcept
{
    std::swap(f_, other.f_);
    std::swap(q_, other.q_);
    std::swap(u_, other.u_);
    nx_ = other.nx_;
    ny_ = other.ny_;
    return *this;
}

// place photon on the images
void Pictures::bin(Photon const& ph, int64_t const xl, int64_t const yl, int64_t const id, double const weight)
{
    // place weighted photon into image location
    if((id == -1 || static_cast<std::uint64_t>(id) == ph.nscat()) && (xl>=0) && (yl >= 0) && ((std::uint32_t)xl < nx_) && ((std::uint32_t)yl < ny_) )
    {
        f_[xl+yl*nx_] += weight * ph.weight() * ph.fi();
        q_[xl+yl*nx_] += weight * ph.weight() * ph.fq();
        u_[xl+yl*nx_] += weight * ph.weight()*ph.fu();
    }
}

void Pictures::normalize(std::uint64_t const numPhotons)
{
    for (std::uint64_t i=0; i!=nx_*ny_; ++i)
    {
        f_[i] /= numPhotons;
        q_[i] /= numPhotons;
        u_[i] /= numPhotons;
    }
}

void Pictures::write(double const phi, double const theta, int const key) const
{
    int const FILENAME_LENGTH{ 40 };
    int const ANGLE_LENGTH{ 10 };

    char fname[FILENAME_LENGTH];
    char phiStr[ANGLE_LENGTH];
    char thetaStr[ANGLE_LENGTH];

    formatAngle(phiStr, ANGLE_LENGTH, phi);
    formatAngle(thetaStr, ANGLE_LENGTH, theta);

    snprintf(fname, FILENAME_LENGTH, "fimage%s_%s_%2.2i.dat", phiStr, thetaStr, key);
    std::ofstream f(fname);
    f.precision(14);

    for (std::uint64_t y=0; y != ny_; ++y)
    {
        for (std::uint64_t x=0; x!=nx_; ++x)
        {
            f << f_[x + y * nx_] << "\t";
        }
        f << "\n";
    }
    f.close();

    snprintf(fname, FILENAME_LENGTH, "qimage%s_%s_%2.2i.dat", phiStr, thetaStr, key);
    std::ofstream q(fname);
    q.precision(14);

    for (std::uint64_t y=0; y != ny_; ++y)
    {
        for (std::uint64_t x=0; x!=nx_; ++x)
        {
            q << q_[x + y * nx_] << "\t";
        }
        q << "\n";
    }
    q.close();

    snprintf(fname, FILENAME_LENGTH, "uimage%s_%s_%2.2i.dat", phiStr, thetaStr, key);
    std::ofstream u(fname);
    u.precision(14);

    for (std::uint64_t y=0; y != ny_; ++y)
    {
        for (std::uint64_t x=0; x!=nx_; ++x)
        {
            u << u_[x + y * nx_] << "\t";
        }
        u << "\n";
    }
    u.close();
}

void Pictures::sum(std::ofstream& file)
{
    double fsum=0, qsum=0, usum=0;
    for (std::uint64_t x=0; x!=nx_; ++x)
    {
        for (std::uint64_t y=0; y != ny_; ++y)
        {
            fsum += f_[y + x * ny_];
            qsum += q_[y + x * ny_];
            usum += u_[y + x * ny_];
        }
    }
    file << "\tF= " << fsum << "\tQ= " << qsum << "\tU= " << usum
         << "\tp= " << std::sqrt(qsum*qsum + usum*usum)/fsum
         << "\tphi= " << 90 * std::atan2(usum, qsum)/PI;
}

Observer::Observer(double const phi, double const theta, double const rimage, std::uint32_t const Nx, std::uint32_t const Ny)
    : result_(Nx, Ny)
    , result0_(Nx, Ny)
    , result1_(Nx, Ny)
    , result2_(Nx, Ny)
    , direction_{phi, theta}
    , nx_(Nx)
    , ny_(Ny)
{
    rimage_ = rimage;
    theta_ = theta;

    cosp_ = std::cos(phi);
    sinp_ = std::sin(phi);
}

void Observer::normalize(std::uint64_t const numPhotons)
{
    result_.normalize(numPhotons);
    result0_.normalize(numPhotons);
    result1_.normalize(numPhotons);
    result2_.normalize(numPhotons);
}

void Observer::writeToMapFiles(bool const fWriteSingleAndDoubleScatterings)
{
    result_.write(direction_.phi(), theta_, 0);

    if (fWriteSingleAndDoubleScatterings)
    {
        result1_.write(direction_.phi(), theta_, 1);
        result2_.write(direction_.phi(), theta_, 2);
    }
}

void Observer::write(std::ofstream& file)
{
    file << "phi= " << degrees(direction_.phi()) << "\ttheta= " << degrees(theta_);
    result_.sum(file);
    result0_.sum(file);
    result1_.sum(file);
    result2_.sum(file);
    file << "\n";
}

bool Observer::inFov(const Photon &photon) const
{
    double const yimage = rimage_ + photon.pos().z() * direction_.sinTheta() -
                          direction_.cosTheta() * (photon.pos().y()*sinp_ + photon.pos().x()*cosp_);

    double const ximage = rimage_ + photon.pos().y()*cosp_ - photon.pos().x()*sinp_;

    auto const xl = static_cast<int64_t>(nx_ * ximage / (2.0 * rimage_));
    auto const yl = static_cast<int64_t>(ny_ * yimage / (2.0 * rimage_));

    return (xl>=0) && (yl >= 0) && ((std::uint32_t)xl < nx_) && ((std::uint32_t)yl < ny_);
}

void Observer::bin(Photon const& photon)
{
    double const yimage = imageY(photon.pos());
    double const ximage = imageX(photon.pos());

    auto const xl = static_cast<int64_t>(nx_ * ximage / (2.0 * rimage_));
    auto const yl = static_cast<int64_t>(ny_ * yimage / (2.0 * rimage_));

    double const eps = std::numeric_limits<float>::epsilon();

    bin(
        photon,
        xl,
        yl,
        photon.nscat() != 0 && std::abs(ximage - xl * (2.0 * rimage_) / nx_) < eps,
        photon.nscat() != 0 && std::abs(yimage - yl * (2.0 * rimage_) / ny_) < eps,
        1.0);
}

// TODO: Add tests for this method
void Observer::bin(Photon const& photon, const Vector3d &pos1, const Vector3d &pos2)
{
    double const yimage1 = imageY(pos1);
    double const ximage1 = imageX(pos1);
    auto const xl1 = static_cast<int64_t>(nx_ * ximage1 / (2.0 * rimage_));
    auto const yl1 = static_cast<int64_t>(ny_ * yimage1 / (2.0 * rimage_));

    double const yimage2 = imageY(pos2);
    double const ximage2 = imageX(pos2);
    auto const xl2 = static_cast<int64_t>(nx_ * ximage2 / (2.0 * rimage_));
    auto const yl2 = static_cast<int64_t>(ny_ * yimage2 / (2.0 * rimage_));

    double const eps = std::numeric_limits<float>::epsilon();

    if (xl1 == xl2 && yl1 == yl2)
    {
        bin(
            photon,
            xl2,
            yl2,
            std::abs(ximage2 - ximage1) < eps && std::abs(ximage2 - xl2 * (2.0 * rimage_) / nx_) < eps,
            std::abs(yimage2 - yimage1) < eps && std::abs(yimage2 - yl2 * (2.0 * rimage_) / ny_) < eps,
            1.0);

        return;
    }

    double xImageMin = std::min(ximage1, ximage2);
    double xImageMax = std::max(ximage1, ximage2);
    int64_t borderX = xl1;
    int64_t lastBorderX = xl2;

    if (ximage1 > ximage2)
    {
        xImageMin = ximage2;
        xImageMax = ximage1;
        borderX = xl2;
        lastBorderX = xl1;
    }

    double yImageMin = yimage1;
    double yImageMax = yimage2;
    int64_t borderY = yl1;
    int64_t lastBorderY = yl2;

    if (yimage1 > yimage2)
    {
        yImageMin = yimage2;
        yImageMax = yimage1;
        borderY = yl2;
        lastBorderY = yl1;
    }

    double const dx = xImageMax - xImageMin;
    double const dy = yImageMax - yImageMin;
    double const totalW = std::sqrt(dx*dx + dy*dy);

    double x = xImageMin;
    double y = yImageMin;

    while (borderX <= lastBorderX && borderY <= lastBorderY)
    {
        double const xborder = std::min(static_cast<double>(borderX+1) * (2.0 * rimage_) / nx_, xImageMax);
        double const yborder = std::min(static_cast<double>(borderY+1) * (2.0 * rimage_) / ny_, yImageMax);

        double const xt = dx > 0 ? (xborder - x) / dx : std::numeric_limits<double>::infinity();
        double const yt = dy > 0 ? (yborder - y) / dy : std::numeric_limits<double>::infinity();

        if (xt < yt)
        {
            double yNew = y + xt * dy;
            double w = std::sqrt((yNew - y)*(yNew-y) + (xborder - x)*(xborder - x));

            bin(
                photon,
                borderX,
                borderY,
                false,
                dy < eps && std::fabs(y - borderY * (2.0 * rimage_) / ny_) < eps,
                w / totalW);

            ++borderX;
            x = xborder;
            y = yNew;
        } else {
            double xNew = x + yt * dx;
            double w = std::sqrt((xNew - x)*(xNew-x) + (yborder - y)*(yborder - y));

            bin(
                photon,
                borderX,
                borderY,
                dx < eps && std::fabs(x - borderX * (2.0 * rimage_) / nx_) < eps,
                false,
                w / totalW);

            ++borderY;
            x = xNew;
            y = yborder;
        }
    }
}

inline double Observer::imageX(Vector3d const &position) const
{
    return rimage_ + position.y() * cosp_ - position.x() * sinp_;
}

inline double Observer::imageY(Vector3d const &position) const
{
    return rimage_ + position.z() * direction_.sinTheta() - direction_.cosTheta() * (position.y()*sinp_ + position.x()*cosp_);
}

inline void Observer::bin(Photon const& photon, int64_t const x, int64_t const y, double const weight)
{
    result_.bin(photon, x, y, -1, weight);
    result0_.bin(photon, x, y, 0, weight);
    result1_.bin(photon, x, y, 1, weight);
    result2_.bin(photon, x, y, 2, weight);
}

inline void Observer::bin(const Photon &photon, int64_t const x, int64_t const y, bool const onXBorder, bool const onYBorder, double const weight)
{
    if (onXBorder && x > 0)
    {
        bin(photon, x, y, 0.5 * weight);
        bin(photon, x-1, y, 0.5 * weight);
    } else if (onYBorder && y > 0) {
        bin(photon, x, y, 0.5 * weight);
        bin(photon, x, y-1, 0.5 * weight);
    } else {
        bin(photon, x, y, weight);
    }
}
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// MOOSE includes
#include "Eigenvalue.h"
#include "EigenProblem.h"
#include "Factory.h"
#include "MooseApp.h"
#include "NonlinearEigenSystem.h"
#include "SlepcSupport.h"

registerMooseObject("MooseApp", Eigenvalue);

defineLegacyParams(Eigenvalue);

InputParameters
Eigenvalue::validParams()
{
  InputParameters params = Steady::validParams();

  params.addClassDescription("Eigenvalue solves a standard/generalized eigenvaue problem");

  params.addParam<bool>(
      "matrix_free",
      false,
      "Whether or not to use a matrix free fashion to form operators. "
      "If true, shell matrices will be used and meanwhile a preconditioning matrix"
      "may be formed as well.");

  params.addParam<bool>("precond_matrix_free",
                        false,
                        "Whether or not to use a matrix free fashion to form preconditioner. "
                        "If true, a shell matrix will be used for preconditioning.");

  params.addParam<bool>("precond_matrix_includes_eigen",
                        false,
                        "Whether or not to include eigen kernels in the preconditioning matrix. "
                        "If true, the preconditioning matrix will include eigen kernels.");

  params.addPrivateParam<bool>("_use_eigen_value", true);

  params.addParam<PostprocessorName>(
      "normalization", "Postprocessor evaluating norm of eigenvector for normalization");
  params.addParam<Real>(
      "normal_factor", 1.0, "Normalize eigenvector to make a defined norm equal to this factor");

// Add slepc options and eigen problems
#ifdef LIBMESH_HAVE_SLEPC
  Moose::SlepcSupport::getSlepcValidParams(params);

  params += Moose::SlepcSupport::getSlepcEigenProblemValidParams();
#endif
  return params;
}

Eigenvalue::Eigenvalue(const InputParameters & parameters)
  : Steady(parameters),
    _eigen_problem(*getCheckedPointerParam<EigenProblem *>(
        "_eigen_problem", "This might happen if you don't have a mesh")),
    _normalization(isParamValid("normalization") ? &getPostprocessorValue("normalization")
                                                 : nullptr)
{
// Extract and store SLEPc options
#if LIBMESH_HAVE_SLEPC
  Moose::SlepcSupport::storeSlepcOptions(_fe_problem, parameters);

  Moose::SlepcSupport::storeSlepcEigenProblemOptions(_eigen_problem, parameters);
  _eigen_problem.setEigenproblemType(_eigen_problem.solverParams()._eigen_problem_type);
#endif

  if (!parameters.isParamValid("normalization") && parameters.isParamSetByUser("normal_factor"))
    paramError("normal_factor",
               "Cannot set scaling factor without defining normalization postprocessor.");
}

void
Eigenvalue::init()
{
  // Set a flag to nonlinear eigen system
  _eigen_problem.getNonlinearEigenSystem().precondMatrixIncludesEigenKernels(
      getParam<bool>("precond_matrix_includes_eigen"));

  Steady::init();
}

void
Eigenvalue::execute()
{
#if LIBMESH_HAVE_SLEPC
#if PETSC_RELEASE_LESS_THAN(3, 12, 0)
  // Make sure the SLEPc options are setup for this app
  Moose::SlepcSupport::slepcSetOptions(_eigen_problem, _pars);
#else
  // Options need to be setup once only
  if (!_eigen_problem.petscOptionsInserted())
  {
    // Master app has the default data base
    if (!_app.isUltimateMaster())
      PetscOptionsPush(_eigen_problem.petscOptionsDatabase());

    Moose::SlepcSupport::slepcSetOptions(_eigen_problem, _pars);

    if (!_app.isUltimateMaster())
      PetscOptionsPop();

    _eigen_problem.petscOptionsInserted() = true;
  }
#endif
#endif

  Steady::execute();
}

void
Eigenvalue::postSolve()
{
#ifdef LIBMESH_HAVE_SLEPC
  if (_normalization)
  {
    Real val = getParam<Real>("normal_factor");

    if (MooseUtils::absoluteFuzzyEqual(*_normalization, 0.0))
      mooseError("Cannot normalize eigenvector by 0");
    else
      val /= *_normalization;

    if (!MooseUtils::absoluteFuzzyEqual(val, 1.0))
    {
      _eigen_problem.scaleEigenvector(val);
      // update all aux variables and user objects
      for (const ExecFlagType & flag : _app.getExecuteOnEnum().items())
        _problem.execute(flag);
    }
  }
#endif
}
<commit_msg>Safe guard NonlinearEigenSystem member function: precondMatrixIncludesEigenKernels<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// MOOSE includes
#include "Eigenvalue.h"
#include "EigenProblem.h"
#include "Factory.h"
#include "MooseApp.h"
#include "NonlinearEigenSystem.h"
#include "SlepcSupport.h"

registerMooseObject("MooseApp", Eigenvalue);

defineLegacyParams(Eigenvalue);

InputParameters
Eigenvalue::validParams()
{
  InputParameters params = Steady::validParams();

  params.addClassDescription("Eigenvalue solves a standard/generalized eigenvaue problem");

  params.addParam<bool>(
      "matrix_free",
      false,
      "Whether or not to use a matrix free fashion to form operators. "
      "If true, shell matrices will be used and meanwhile a preconditioning matrix"
      "may be formed as well.");

  params.addParam<bool>("precond_matrix_free",
                        false,
                        "Whether or not to use a matrix free fashion to form preconditioner. "
                        "If true, a shell matrix will be used for preconditioning.");

  params.addParam<bool>("precond_matrix_includes_eigen",
                        false,
                        "Whether or not to include eigen kernels in the preconditioning matrix. "
                        "If true, the preconditioning matrix will include eigen kernels.");

  params.addPrivateParam<bool>("_use_eigen_value", true);

  params.addParam<PostprocessorName>(
      "normalization", "Postprocessor evaluating norm of eigenvector for normalization");
  params.addParam<Real>(
      "normal_factor", 1.0, "Normalize eigenvector to make a defined norm equal to this factor");

// Add slepc options and eigen problems
#ifdef LIBMESH_HAVE_SLEPC
  Moose::SlepcSupport::getSlepcValidParams(params);

  params += Moose::SlepcSupport::getSlepcEigenProblemValidParams();
#endif
  return params;
}

Eigenvalue::Eigenvalue(const InputParameters & parameters)
  : Steady(parameters),
    _eigen_problem(*getCheckedPointerParam<EigenProblem *>(
        "_eigen_problem", "This might happen if you don't have a mesh")),
    _normalization(isParamValid("normalization") ? &getPostprocessorValue("normalization")
                                                 : nullptr)
{
// Extract and store SLEPc options
#if LIBMESH_HAVE_SLEPC
  Moose::SlepcSupport::storeSlepcOptions(_fe_problem, parameters);

  Moose::SlepcSupport::storeSlepcEigenProblemOptions(_eigen_problem, parameters);
  _eigen_problem.setEigenproblemType(_eigen_problem.solverParams()._eigen_problem_type);
#endif

  if (!parameters.isParamValid("normalization") && parameters.isParamSetByUser("normal_factor"))
    paramError("normal_factor",
               "Cannot set scaling factor without defining normalization postprocessor.");
}

void
Eigenvalue::init()
{
#if LIBMESH_HAVE_SLEPC
  // Set a flag to nonlinear eigen system
  _eigen_problem.getNonlinearEigenSystem().precondMatrixIncludesEigenKernels(
      getParam<bool>("precond_matrix_includes_eigen"));
#endif
  Steady::init();
}

void
Eigenvalue::execute()
{
#if LIBMESH_HAVE_SLEPC
#if PETSC_RELEASE_LESS_THAN(3, 12, 0)
  // Make sure the SLEPc options are setup for this app
  Moose::SlepcSupport::slepcSetOptions(_eigen_problem, _pars);
#else
  // Options need to be setup once only
  if (!_eigen_problem.petscOptionsInserted())
  {
    // Master app has the default data base
    if (!_app.isUltimateMaster())
      PetscOptionsPush(_eigen_problem.petscOptionsDatabase());

    Moose::SlepcSupport::slepcSetOptions(_eigen_problem, _pars);

    if (!_app.isUltimateMaster())
      PetscOptionsPop();

    _eigen_problem.petscOptionsInserted() = true;
  }
#endif
#endif

  Steady::execute();
}

void
Eigenvalue::postSolve()
{
#ifdef LIBMESH_HAVE_SLEPC
  if (_normalization)
  {
    Real val = getParam<Real>("normal_factor");

    if (MooseUtils::absoluteFuzzyEqual(*_normalization, 0.0))
      mooseError("Cannot normalize eigenvector by 0");
    else
      val /= *_normalization;

    if (!MooseUtils::absoluteFuzzyEqual(val, 1.0))
    {
      _eigen_problem.scaleEigenvector(val);
      // update all aux variables and user objects
      for (const ExecFlagType & flag : _app.getExecuteOnEnum().items())
        _problem.execute(flag);
    }
  }
#endif
}
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "FunctionDT.h"
#include "FEProblem.h"
#include "Transient.h"

template<>
InputParameters validParams<FunctionDT>()
{
  InputParameters params = validParams<TimeStepper>();
  params.addRequiredParam<std::vector<Real> >("time_t", "The values of t");
  params.addRequiredParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", 2, "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.");
  params.addParam<Real>("min_dt", 0, "The minimal dt to take.");
  params.addParam<bool>("interpolate", true, "Whether or not to interpolate DT between times.  This is true by default for historical reasons.");

  return params;
}

FunctionDT::FunctionDT(const InputParameters & parameters) :
    TimeStepper(parameters),
    _time_t(getParam<std::vector<Real> >("time_t")),
    _time_dt(getParam<std::vector<Real> >("time_dt")),
    _time_ipol(_time_t, getParam<std::vector<Real> >("time_dt")),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false),
    _min_dt(getParam<Real>("min_dt")),
    _interpolate(getParam<bool>("interpolate"))
{
  _time_knots = _time_t;
}

void
FunctionDT::init()
{
}

void
FunctionDT::removeOldKnots()
{
  while ((_time_knots.size() > 0) && (*_time_knots.begin() <= _time || std::abs(*_time_knots.begin() - _time) < 1e-10))
    _time_knots.erase(_time_knots.begin());
}

void
FunctionDT::preExecute()
{
  TimeStepper::preExecute();
  removeOldKnots();
}

Real
FunctionDT::computeInitialDT()
{
  return computeDT();
}

Real
FunctionDT::computeDT()
{
  Real local_dt = 0;

  if (_interpolate)
    local_dt = _time_ipol.sample(_time);
  else // Find where we are
  {
    unsigned int i = 0;
    if (MooseUtils::relativeFuzzyGreaterEqual(_time, _time_t.back()))
    {
      i = _time_t.size();
    }
    else
    {
      for (; i < _time_t.size() - 1; i++)
        if (MooseUtils::relativeFuzzyLessThan(_time, _time_t[i + 1]))
          break;
    }

    // Use the last dt after the end
    if (i == _time_t.size())
      local_dt = _time_dt.back();
    else
      local_dt = _time_dt[i];
  }

  // sync to time knot
  if ((_time_knots.size() > 0) && (_time + local_dt >= (*_time_knots.begin())))
    local_dt = (*_time_knots.begin()) - _time;
  // honor minimal dt
  if (local_dt < _min_dt)
    local_dt = _min_dt;

//  if (_cutback_occurred && (local_dt > _dt * _growth_factor))
//    local_dt = _dt * _growth_factor;
  _cutback_occurred = false;

  return local_dt;
}

void
FunctionDT::postStep()
{
  removeOldKnots();
}

void
FunctionDT::rejectStep()
{
  _cutback_occurred = true;
  TimeStepper::rejectStep();
}
<commit_msg>Re-enable the maximum timestep growth in FunctionDT (#7497)<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "FunctionDT.h"
#include "FEProblem.h"
#include "Transient.h"
#include <limits>

template<>
InputParameters validParams<FunctionDT>()
{
  InputParameters params = validParams<TimeStepper>();
  params.addRequiredParam<std::vector<Real> >("time_t", "The values of t");
  params.addRequiredParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", std::numeric_limits<Real>::max(), "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.");
  params.addParam<Real>("min_dt", 0, "The minimal dt to take.");
  params.addParam<bool>("interpolate", true, "Whether or not to interpolate DT between times.  This is true by default for historical reasons.");

  return params;
}

FunctionDT::FunctionDT(const InputParameters & parameters) :
    TimeStepper(parameters),
    _time_t(getParam<std::vector<Real> >("time_t")),
    _time_dt(getParam<std::vector<Real> >("time_dt")),
    _time_ipol(_time_t, getParam<std::vector<Real> >("time_dt")),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false),
    _min_dt(getParam<Real>("min_dt")),
    _interpolate(getParam<bool>("interpolate"))
{
  _time_knots = _time_t;
}

void
FunctionDT::init()
{
}

void
FunctionDT::removeOldKnots()
{
  while ((_time_knots.size() > 0) && (*_time_knots.begin() <= _time || std::abs(*_time_knots.begin() - _time) < 1e-10))
    _time_knots.erase(_time_knots.begin());
}

void
FunctionDT::preExecute()
{
  TimeStepper::preExecute();
  removeOldKnots();
}

Real
FunctionDT::computeInitialDT()
{
  return computeDT();
}

Real
FunctionDT::computeDT()
{
  Real local_dt = 0;

  if (_interpolate)
    local_dt = _time_ipol.sample(_time);
  else // Find where we are
  {
    unsigned int i = 0;
    if (MooseUtils::relativeFuzzyGreaterEqual(_time, _time_t.back()))
    {
      i = _time_t.size();
    }
    else
    {
      for (; i < _time_t.size() - 1; i++)
        if (MooseUtils::relativeFuzzyLessThan(_time, _time_t[i + 1]))
          break;
    }

    // Use the last dt after the end
    if (i == _time_t.size())
      local_dt = _time_dt.back();
    else
      local_dt = _time_dt[i];
  }

  // sync to time knot
  if ((_time_knots.size() > 0) && (_time + local_dt >= (*_time_knots.begin())))
    local_dt = (*_time_knots.begin()) - _time;
  // honor minimal dt
  if (local_dt < _min_dt)
    local_dt = _min_dt;

  if (_cutback_occurred && (local_dt > _dt * _growth_factor))
    local_dt = _dt * _growth_factor;
  _cutback_occurred = false;

  return local_dt;
}

void
FunctionDT::postStep()
{
  removeOldKnots();
}

void
FunctionDT::rejectStep()
{
  _cutback_occurred = true;
  TimeStepper::rejectStep();
}
<|endoftext|>


<commit_before>// @(#)root/tree:$Id$
// Author: Rene Brun   05/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// A TSelector object is used by the TTree::Draw, TTree::Scan,            //
// TTree::Process to navigate in a TTree and make selections.             //
// It contains the following main methods:                                //
//                                                                        //
// void TSelector::Init(TTree *t). Called every time a new TTree is       //
//    attached.                                                           //
//                                                                        //
// void TSelector::SlaveBegin(). Create e.g. histograms in this method.   //
//    This method is called (with or without PROOF) before looping on the //
//    entries in the Tree. When using PROOF, this method is called on     //
//    each worker node.                                                   //
// void TSelector::Begin(). Mostly for backward compatibility; use        //
//    SlaveBegin() instead. Both methods are called before looping on the //
//    entries in the Tree. When using PROOF, Begin() is called on the     //
//    client only.                                                        //
//                                                                        //
// Bool_t TSelector::Notify(). This method is called at the first entry   //
//    of a new file in a chain.                                           //
//                                                                        //
// Bool_t TSelector::Process(Long64_t entry). This method is called       //
//    to process an entry. It is the user's responsability to read        //
//    the corresponding entry in memory (may be just a partial read).     //
//    Once the entry is in memory one can apply a selection and if the    //
//    entry is selected histograms can be filled. Processing stops        //
//    when this function returns kFALSE. This function combines the       //
//    next two functions in one, avoiding to have to maintain state       //
//    in the class to communicate between these two functions.            //
//    See WARNING below about entry.                                      //
//    This method is used by PROOF.                                       //
// Bool_t TSelector::ProcessCut(Long64_t entry). This method is called    //
//    before processing entry. It is the user's responsability to read    //
//    the corresponding entry in memory (may be just a partial read).     //
//    The function returns kTRUE if the entry must be processed,          //
//    kFALSE otherwise. This method is obsolete, use Process().           //
//    See WARNING below about entry.                                      //
// void TSelector::ProcessFill(Long64_t entry). This method is called     //
//    for all selected entries. User fills histograms in this function.   //
//    This method is obsolete, use Process().                             //
//    See WARNING below about entry.                                      //
// void TSelector::SlaveTerminate(). This method is called at the end of  //
//    the loop on all PROOF worker nodes. In local mode this method is    //
//    called on the client too.                                           //
// void TSelector::Terminate(). This method is called at the end of       //
//    the loop on all entries. When using PROOF Terminate() is call on    //
//    the client only. Typically one performs the fits on the produced    //
//    histograms or write the histograms to file in this method.          //
//                                                                        //
// WARNING when a selector is used with a TChain:                         //
//    in the Process, ProcessCut, ProcessFill function, you must use      //
//    the pointer to the current Tree to call GetEntry(entry).            //
//    entry is always the local entry number in the current tree.         //
//    Assuming that fChain is the pointer to the TChain being processed,  //
//    use fChain->GetTree()->GetEntry(entry);                             //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TSystem.h"
#include "TTree.h"
#include "TError.h"
#include "TSelectorCint.h"
#include "TClass.h"
#include "TInterpreter.h"

ClassImp(TSelector)

//______________________________________________________________________________
TSelector::TSelector() : TObject()
{
   // Default selector ctor.

   fStatus = 0;
   fAbort  = kContinue;
   fObject = 0;
   fInput  = 0;
   fOutput = new TSelectorList;
   fOutput->SetOwner();
}

//______________________________________________________________________________
TSelector::~TSelector()
{
   // Selector destructor.

   delete fOutput;
}

//______________________________________________________________________________
void TSelector::Abort(const char *why, EAbort what)
{
   // Abort processing. If what = kAbortProcess, the Process() loop will be
   // aborted. If what = kAbortFile, the current file in a chain will be
   // aborted and the processing will continue with the next file, if there
   // is no next file then Process() will be aborted. Abort() can also  be
   // called from Begin(), SlaveBegin(), Init() and Notify(). After abort
   // the SlaveTerminate() and Terminate() are always called. The abort flag
   // can be checked in these methods using GetAbort().

   fAbort = what;
   TString mess = "Abort";
   if (fAbort == kAbortProcess)
      mess = "AbortProcess";
   else if (fAbort == kAbortFile)
      mess = "AbortFile";

   Info(mess, "%s", why);
}

//______________________________________________________________________________
TSelector *TSelector::GetSelector(const char *filename)
{
   // The code in filename is loaded (interpreted or compiled, see below),
   // filename must contain a valid class implementation derived from TSelector.
   //
   // If filename is of the form file.C, the file will be interpreted.
   // If filename is of the form file.C++, the file file.C will be compiled
   // and dynamically loaded. The corresponding binary file and shared
   // library will be deleted at the end of the function.
   // If filename is of the form file.C+, the file file.C will be compiled
   // and dynamically loaded. At next call, if file.C is older than file.o
   // and file.so, the file.C is not compiled, only file.so is loaded.
   //
   // The static function returns a pointer to a TSelector object

   // If the filename does not contain "." assume class is compiled in
   TString localname;
   Bool_t fromFile = kFALSE;
   if (strchr(filename, '.') != 0) {
      //Interpret/compile filename via CINT
      localname  = ".L ";
      localname += filename;
      gROOT->ProcessLine(localname);
      fromFile = kTRUE;
   }

   //loop on all classes known to CINT to find the class on filename
   //that derives from TSelector
   const char *basename = gSystem->BaseName(filename);
   if (!basename) {
      ::Error("TSelector::GetSelector","unable to determine the classname for file %s", filename);
      return 0;
   }
   TString aclicmode,args,io;
   localname = gSystem->SplitAclicMode(basename,aclicmode,args,io);
   Bool_t isCompiled = !fromFile || aclicmode.Length()>0;
   if (localname.Last('.') != kNPOS)
      localname.Remove(localname.Last('.'));

   // if a file was not specified, try to load the class via the interpreter;
   // this returns 0 (== failure) in the case the class is already in memory
   // but does not have a dictionary, so we just raise a flag for better
   // diagnostic in the case the class is not found in the CINT ClassInfo table.
   Bool_t autoloaderr = kFALSE;
   if (!fromFile && gCling->AutoLoad(localname) != 1)
      autoloaderr = kTRUE;

   ClassInfo_t *cl = gCling->ClassInfo_Factory(localname);
   Bool_t ok = kFALSE;
   Bool_t nameFound = kFALSE;
   if (cl && gCling->ClassInfo_IsValid(cl)) {
      if (localname == gCling->ClassInfo_FullName(cl)) {
         nameFound = kTRUE;
         if (gCling->ClassInfo_IsBase(cl,"TSelector")) ok = kTRUE;
      }
   }
   if (!ok) {
      if (fromFile) {
         if (nameFound) {
            ::Error("TSelector::GetSelector",
                    "The class %s in file %s does not derive from TSelector.", localname.Data(), filename);
         } else {
            ::Error("TSelector::GetSelector",
                    "The file %s does not define a class named %s.", filename, localname.Data());
         }
      } else {
         if (autoloaderr)
            ::Error("TSelector::GetSelector", "class %s could not be loaded", filename);
         else
            ::Error("TSelector::GetSelector",
                    "class %s does not exist or does not derive from TSelector", filename);
      }
      gCling->ClassInfo_Delete(cl);
      return 0;
   }

   // we can now create an instance of the class
   TSelector *selector = (TSelector*)gCling->ClassInfo_New(cl);
   if (!selector || isCompiled) {
      gCling->ClassInfo_Delete(cl);
      return selector;
   }

   //interpreted selector: cannot be used as such
   //create a fake selector
   TSelectorCint *select = new TSelectorCint();
   select->Build(selector, cl);
   gCling->ClassInfo_Delete(cl);
   return select;
}

//______________________________________________________________________________
Bool_t TSelector::IsStandardDraw(const char *selec)
{
   // Find out if this is a standard selection used for Draw actions
   // (either TSelectorDraw, TProofDraw or deriving from them).

   // Make sure we have a name
   if (!selec) {
      ::Info("TSelector::IsStandardDraw",
             "selector name undefined - do nothing");
      return kFALSE;
   }

   Bool_t stdselec = kFALSE;
   if (!strchr(selec, '.')) {
      if (strstr(selec, "TSelectorDraw")) {
         stdselec = kTRUE;
      } else {
         TClass *cl = TClass::GetClass(selec);
         if (cl && (cl->InheritsFrom("TProofDraw") ||
                    cl->InheritsFrom("TSelectorDraw")))
            stdselec = kTRUE;
      }
   }

   // We are done
   return stdselec;
}

Bool_t TSelector::ProcessCut(Long64_t /*entry*/)
{
   //    This method is called before processing entry. It is the user's responsability to read
   //    the corresponding entry in memory (may be just a partial read).
   //    The function returns kTRUE if the entry must be processed,
   //    kFALSE otherwise. This method is obsolete, use Process().
   //
   // WARNING when a selector is used with a TChain:
   //    in the Process, ProcessCut, ProcessFill function, you must use
   //    the pointer to the current Tree to call GetEntry(entry).
   //    entry is always the local entry number in the current tree.
   //    Assuming that fChain is the pointer to the TChain being processed,
   //    use fChain->GetTree()->GetEntry(entry);

   return kTRUE;
}

void TSelector::ProcessFill(Long64_t /*entry*/)
{
   // This method is called for all selected entries. User fills histograms
   // in this function.  This method is obsolete, use Process().
   //
   // WARNING when a selector is used with a TChain:
   //    in the Process, ProcessCut, ProcessFill function, you must use
   //    the pointer to the current Tree to call GetEntry(entry).
   //    entry is always the local entry number in the current tree.
   //    Assuming that fChain is the pointer to the TChain being processed,
   //    use fChain->GetTree()->GetEntry(entry);
}

Bool_t TSelector::Process(Long64_t /*entry*/) {
   // The Process() function is called for each entry in the tree (or possibly
   // keyed object in the case of PROOF) to be processed. The entry argument
   // specifies which entry in the currently loaded tree is to be processed.
   // It can be passed to either t01::GetEntry() or TBranch::GetEntry()
   // to read either all or the required parts of the data. When processing
   // keyed objects with PROOF, the object is already loaded and is available
   // via the fObject pointer.
   //
   // This function should contain the "body" of the analysis. It can contain
   // simple or elaborate selection criteria, run algorithms on the data
   // of the event and typically fill histograms.
   //
   // The processing can be stopped by calling Abort().
   //
   // Use fStatus to set the return value of TTree::Process().
   //
   // The return value is currently not used.

   return kFALSE;
}

<commit_msg>Use TClass::New in TSelector::GetSelector.<commit_after>// @(#)root/tree:$Id$
// Author: Rene Brun   05/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// A TSelector object is used by the TTree::Draw, TTree::Scan,            //
// TTree::Process to navigate in a TTree and make selections.             //
// It contains the following main methods:                                //
//                                                                        //
// void TSelector::Init(TTree *t). Called every time a new TTree is       //
//    attached.                                                           //
//                                                                        //
// void TSelector::SlaveBegin(). Create e.g. histograms in this method.   //
//    This method is called (with or without PROOF) before looping on the //
//    entries in the Tree. When using PROOF, this method is called on     //
//    each worker node.                                                   //
// void TSelector::Begin(). Mostly for backward compatibility; use        //
//    SlaveBegin() instead. Both methods are called before looping on the //
//    entries in the Tree. When using PROOF, Begin() is called on the     //
//    client only.                                                        //
//                                                                        //
// Bool_t TSelector::Notify(). This method is called at the first entry   //
//    of a new file in a chain.                                           //
//                                                                        //
// Bool_t TSelector::Process(Long64_t entry). This method is called       //
//    to process an entry. It is the user's responsability to read        //
//    the corresponding entry in memory (may be just a partial read).     //
//    Once the entry is in memory one can apply a selection and if the    //
//    entry is selected histograms can be filled. Processing stops        //
//    when this function returns kFALSE. This function combines the       //
//    next two functions in one, avoiding to have to maintain state       //
//    in the class to communicate between these two functions.            //
//    See WARNING below about entry.                                      //
//    This method is used by PROOF.                                       //
// Bool_t TSelector::ProcessCut(Long64_t entry). This method is called    //
//    before processing entry. It is the user's responsability to read    //
//    the corresponding entry in memory (may be just a partial read).     //
//    The function returns kTRUE if the entry must be processed,          //
//    kFALSE otherwise. This method is obsolete, use Process().           //
//    See WARNING below about entry.                                      //
// void TSelector::ProcessFill(Long64_t entry). This method is called     //
//    for all selected entries. User fills histograms in this function.   //
//    This method is obsolete, use Process().                             //
//    See WARNING below about entry.                                      //
// void TSelector::SlaveTerminate(). This method is called at the end of  //
//    the loop on all PROOF worker nodes. In local mode this method is    //
//    called on the client too.                                           //
// void TSelector::Terminate(). This method is called at the end of       //
//    the loop on all entries. When using PROOF Terminate() is call on    //
//    the client only. Typically one performs the fits on the produced    //
//    histograms or write the histograms to file in this method.          //
//                                                                        //
// WARNING when a selector is used with a TChain:                         //
//    in the Process, ProcessCut, ProcessFill function, you must use      //
//    the pointer to the current Tree to call GetEntry(entry).            //
//    entry is always the local entry number in the current tree.         //
//    Assuming that fChain is the pointer to the TChain being processed,  //
//    use fChain->GetTree()->GetEntry(entry);                             //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TSystem.h"
#include "TTree.h"
#include "TError.h"
#include "TSelectorCint.h"
#include "TClass.h"
#include "TInterpreter.h"

ClassImp(TSelector)

//______________________________________________________________________________
TSelector::TSelector() : TObject()
{
   // Default selector ctor.

   fStatus = 0;
   fAbort  = kContinue;
   fObject = 0;
   fInput  = 0;
   fOutput = new TSelectorList;
   fOutput->SetOwner();
}

//______________________________________________________________________________
TSelector::~TSelector()
{
   // Selector destructor.

   delete fOutput;
}

//______________________________________________________________________________
void TSelector::Abort(const char *why, EAbort what)
{
   // Abort processing. If what = kAbortProcess, the Process() loop will be
   // aborted. If what = kAbortFile, the current file in a chain will be
   // aborted and the processing will continue with the next file, if there
   // is no next file then Process() will be aborted. Abort() can also  be
   // called from Begin(), SlaveBegin(), Init() and Notify(). After abort
   // the SlaveTerminate() and Terminate() are always called. The abort flag
   // can be checked in these methods using GetAbort().

   fAbort = what;
   TString mess = "Abort";
   if (fAbort == kAbortProcess)
      mess = "AbortProcess";
   else if (fAbort == kAbortFile)
      mess = "AbortFile";

   Info(mess, "%s", why);
}

//______________________________________________________________________________
TSelector *TSelector::GetSelector(const char *filename)
{
   // The code in filename is loaded (interpreted or compiled, see below),
   // filename must contain a valid class implementation derived from TSelector.
   //
   // If filename is of the form file.C, the file will be interpreted.
   // If filename is of the form file.C++, the file file.C will be compiled
   // and dynamically loaded. The corresponding binary file and shared
   // library will be deleted at the end of the function.
   // If filename is of the form file.C+, the file file.C will be compiled
   // and dynamically loaded. At next call, if file.C is older than file.o
   // and file.so, the file.C is not compiled, only file.so is loaded.
   //
   // The static function returns a pointer to a TSelector object

   // If the filename does not contain "." assume class is compiled in
   TString localname;
   Bool_t fromFile = kFALSE;
   if (strchr(filename, '.') != 0) {
      //Interpret/compile filename via CINT
      localname  = ".L ";
      localname += filename;
      gROOT->ProcessLine(localname);
      fromFile = kTRUE;
   }

   //loop on all classes known to CINT to find the class on filename
   //that derives from TSelector
   const char *basename = gSystem->BaseName(filename);
   if (!basename) {
      ::Error("TSelector::GetSelector","unable to determine the classname for file %s", filename);
      return 0;
   }
   TString aclicmode,args,io;
   localname = gSystem->SplitAclicMode(basename,aclicmode,args,io);
   if (localname.Last('.') != kNPOS)
      localname.Remove(localname.Last('.'));

   // if a file was not specified, try to load the class via the interpreter;
   // this returns 0 (== failure) in the case the class is already in memory
   // but does not have a dictionary, so we just raise a flag for better
   // diagnostic in the case the class is not found in the CINT ClassInfo table.
   Bool_t autoloaderr = kFALSE;
   if (!fromFile && gCling->AutoLoad(localname) != 1)
      autoloaderr = kTRUE;

   TClass *selCl = TClass::GetClass(localname);
   if (selCl) {
      // We have all we need.
      auto offset = selCl->GetBaseClassOffset(TSelector::Class());
      if (offset == -1) {
         // TSelector is not a based class.
         if (fromFile)
            ::Error("TSelector::GetSelector",
                    "The class %s in file %s does not derive from TSelector.", localname.Data(), filename);
         else if (autoloaderr)
            ::Error("TSelector::GetSelector", "class %s could not be loaded", filename);
         else
            ::Error("TSelector::GetSelector",
                    "class %s does not exist or does not derive from TSelector", filename);
         return 0;
      }
      char *result = (char*)selCl->New();
      // By adding offset, we support the case where TSelector is not the
      // "left-most" base class (i.e. offset != 0)
      return (TSelector*)(result+offset);

   } else {
      ClassInfo_t *cl = gCling->ClassInfo_Factory(localname);
      Bool_t ok = kFALSE;
      Bool_t nameFound = kFALSE;
      if (cl && gCling->ClassInfo_IsValid(cl)) {
         if (localname == gCling->ClassInfo_FullName(cl)) {
            nameFound = kTRUE;
            if (gCling->ClassInfo_IsBase(cl,"TSelector")) ok = kTRUE;
         }
      }
      if (!ok) {
         if (fromFile) {
            if (nameFound) {
               ::Error("TSelector::GetSelector",
                       "The class %s in file %s does not derive from TSelector.", localname.Data(), filename);
            } else {
               ::Error("TSelector::GetSelector",
                       "The file %s does not define a class named %s.", filename, localname.Data());
            }
         } else {
            if (autoloaderr)
               ::Error("TSelector::GetSelector", "class %s could not be loaded", filename);
            else
               ::Error("TSelector::GetSelector",
                       "class %s does not exist or does not derive from TSelector", filename);
         }
         gCling->ClassInfo_Delete(cl);
         return 0;
      }

      // we can now create an instance of the class
      TSelector *selector = (TSelector*)gCling->ClassInfo_New(cl);
      gCling->ClassInfo_Delete(cl);
      return selector;
   }
}

//______________________________________________________________________________
Bool_t TSelector::IsStandardDraw(const char *selec)
{
   // Find out if this is a standard selection used for Draw actions
   // (either TSelectorDraw, TProofDraw or deriving from them).

   // Make sure we have a name
   if (!selec) {
      ::Info("TSelector::IsStandardDraw",
             "selector name undefined - do nothing");
      return kFALSE;
   }

   Bool_t stdselec = kFALSE;
   if (!strchr(selec, '.')) {
      if (strstr(selec, "TSelectorDraw")) {
         stdselec = kTRUE;
      } else {
         TClass *cl = TClass::GetClass(selec);
         if (cl && (cl->InheritsFrom("TProofDraw") ||
                    cl->InheritsFrom("TSelectorDraw")))
            stdselec = kTRUE;
      }
   }

   // We are done
   return stdselec;
}

Bool_t TSelector::ProcessCut(Long64_t /*entry*/)
{
   //    This method is called before processing entry. It is the user's responsability to read
   //    the corresponding entry in memory (may be just a partial read).
   //    The function returns kTRUE if the entry must be processed,
   //    kFALSE otherwise. This method is obsolete, use Process().
   //
   // WARNING when a selector is used with a TChain:
   //    in the Process, ProcessCut, ProcessFill function, you must use
   //    the pointer to the current Tree to call GetEntry(entry).
   //    entry is always the local entry number in the current tree.
   //    Assuming that fChain is the pointer to the TChain being processed,
   //    use fChain->GetTree()->GetEntry(entry);

   return kTRUE;
}

void TSelector::ProcessFill(Long64_t /*entry*/)
{
   // This method is called for all selected entries. User fills histograms
   // in this function.  This method is obsolete, use Process().
   //
   // WARNING when a selector is used with a TChain:
   //    in the Process, ProcessCut, ProcessFill function, you must use
   //    the pointer to the current Tree to call GetEntry(entry).
   //    entry is always the local entry number in the current tree.
   //    Assuming that fChain is the pointer to the TChain being processed,
   //    use fChain->GetTree()->GetEntry(entry);
}

Bool_t TSelector::Process(Long64_t /*entry*/) {
   // The Process() function is called for each entry in the tree (or possibly
   // keyed object in the case of PROOF) to be processed. The entry argument
   // specifies which entry in the currently loaded tree is to be processed.
   // It can be passed to either t01::GetEntry() or TBranch::GetEntry()
   // to read either all or the required parts of the data. When processing
   // keyed objects with PROOF, the object is already loaded and is available
   // via the fObject pointer.
   //
   // This function should contain the "body" of the analysis. It can contain
   // simple or elaborate selection criteria, run algorithms on the data
   // of the event and typically fill histograms.
   //
   // The processing can be stopped by calling Abort().
   //
   // Use fStatus to set the return value of TTree::Process().
   //
   // The return value is currently not used.

   return kFALSE;
}

<|endoftext|>


<commit_before>//===- CorrelatedValuePropagation.cpp - Propagate CFG-derived info --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Correlated Value Propagation pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;

#define DEBUG_TYPE "correlated-value-propagation"

STATISTIC(NumPhis,      "Number of phis propagated");
STATISTIC(NumSelects,   "Number of selects propagated");
STATISTIC(NumMemAccess, "Number of memory access targets propagated");
STATISTIC(NumCmps,      "Number of comparisons propagated");
STATISTIC(NumReturns,   "Number of return values propagated");
STATISTIC(NumDeadCases, "Number of switch cases removed");

namespace {
  class CorrelatedValuePropagation : public FunctionPass {
    LazyValueInfo *LVI;

    bool processSelect(SelectInst *SI);
    bool processPHI(PHINode *P);
    bool processMemAccess(Instruction *I);
    bool processCmp(CmpInst *C);
    bool processSwitch(SwitchInst *SI);
    bool processCallSite(CallSite CS);

    /// Return a constant value for V usable at At and everything it
    /// dominates.  If no such Constant can be found, return nullptr.
    Constant *getConstantAt(Value *V, Instruction *At);

  public:
    static char ID;
    CorrelatedValuePropagation(): FunctionPass(ID) {
     initializeCorrelatedValuePropagationPass(*PassRegistry::getPassRegistry());
    }

    bool runOnFunction(Function &F) override;

    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.addRequired<LazyValueInfo>();
      AU.addPreserved<GlobalsAAWrapperPass>();
    }
  };
}

char CorrelatedValuePropagation::ID = 0;
INITIALIZE_PASS_BEGIN(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)
INITIALIZE_PASS_DEPENDENCY(LazyValueInfo)
INITIALIZE_PASS_END(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)

// Public interface to the Value Propagation pass
Pass *llvm::createCorrelatedValuePropagationPass() {
  return new CorrelatedValuePropagation();
}

bool CorrelatedValuePropagation::processSelect(SelectInst *S) {
  if (S->getType()->isVectorTy()) return false;
  if (isa<Constant>(S->getOperand(0))) return false;

  Constant *C = LVI->getConstant(S->getOperand(0), S->getParent(), S);
  if (!C) return false;

  ConstantInt *CI = dyn_cast<ConstantInt>(C);
  if (!CI) return false;

  Value *ReplaceWith = S->getOperand(1);
  Value *Other = S->getOperand(2);
  if (!CI->isOne()) std::swap(ReplaceWith, Other);
  if (ReplaceWith == S) ReplaceWith = UndefValue::get(S->getType());

  S->replaceAllUsesWith(ReplaceWith);
  S->eraseFromParent();

  ++NumSelects;

  return true;
}

bool CorrelatedValuePropagation::processPHI(PHINode *P) {
  bool Changed = false;

  BasicBlock *BB = P->getParent();
  for (unsigned i = 0, e = P->getNumIncomingValues(); i < e; ++i) {
    Value *Incoming = P->getIncomingValue(i);
    if (isa<Constant>(Incoming)) continue;

    Value *V = LVI->getConstantOnEdge(Incoming, P->getIncomingBlock(i), BB, P);

    // Look if the incoming value is a select with a scalar condition for which
    // LVI can tells us the value. In that case replace the incoming value with
    // the appropriate value of the select. This often allows us to remove the
    // select later.
    if (!V) {
      SelectInst *SI = dyn_cast<SelectInst>(Incoming);
      if (!SI) continue;

      Value *Condition = SI->getCondition();
      if (!Condition->getType()->isVectorTy()) {
        if (Constant *C = LVI->getConstantOnEdge(
                Condition, P->getIncomingBlock(i), BB, P)) {
          if (C->isOneValue()) {
            V = SI->getTrueValue();
          } else if (C->isZeroValue()) {
            V = SI->getFalseValue();
          }
          // Once LVI learns to handle vector types, we could also add support
          // for vector type constants that are not all zeroes or all ones.
        }
      }

      // Look if the select has a constant but LVI tells us that the incoming
      // value can never be that constant. In that case replace the incoming
      // value with the other value of the select. This often allows us to
      // remove the select later.
      if (!V) {
        Constant *C = dyn_cast<Constant>(SI->getFalseValue());
        if (!C) continue;

        if (LVI->getPredicateOnEdge(ICmpInst::ICMP_EQ, SI, C,
              P->getIncomingBlock(i), BB, P) !=
            LazyValueInfo::False)
          continue;
        V = SI->getTrueValue();
      }

      DEBUG(dbgs() << "CVP: Threading PHI over " << *SI << '\n');
    }

    P->setIncomingValue(i, V);
    Changed = true;
  }

  // FIXME: Provide TLI, DT, AT to SimplifyInstruction.
  const DataLayout &DL = BB->getModule()->getDataLayout();
  if (Value *V = SimplifyInstruction(P, DL)) {
    P->replaceAllUsesWith(V);
    P->eraseFromParent();
    Changed = true;
  }

  if (Changed)
    ++NumPhis;

  return Changed;
}

bool CorrelatedValuePropagation::processMemAccess(Instruction *I) {
  Value *Pointer = nullptr;
  if (LoadInst *L = dyn_cast<LoadInst>(I))
    Pointer = L->getPointerOperand();
  else
    Pointer = cast<StoreInst>(I)->getPointerOperand();

  if (isa<Constant>(Pointer)) return false;

  Constant *C = LVI->getConstant(Pointer, I->getParent(), I);
  if (!C) return false;

  ++NumMemAccess;
  I->replaceUsesOfWith(Pointer, C);
  return true;
}

/// processCmp - See if LazyValueInfo's ability to exploit edge conditions,
/// or range information is sufficient to prove this comparison.  Even for
/// local conditions, this can sometimes prove conditions instcombine can't by
/// exploiting range information.
bool CorrelatedValuePropagation::processCmp(CmpInst *C) {
  Value *Op0 = C->getOperand(0);
  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return false;

  // As a policy choice, we choose not to waste compile time on anything where
  // the comparison is testing local values.  While LVI can sometimes reason
  // about such cases, it's not its primary purpose.  We do make sure to do
  // the block local query for uses from terminator instructions, but that's
  // handled in the code for each terminator.
  auto *I = dyn_cast<Instruction>(Op0);
  if (I && I->getParent() == C->getParent())
    return false;

  LazyValueInfo::Tristate Result =
    LVI->getPredicateAt(C->getPredicate(), Op0, Op1, C);
  if (Result == LazyValueInfo::Unknown) return false;

  ++NumCmps;
  if (Result == LazyValueInfo::True)
    C->replaceAllUsesWith(ConstantInt::getTrue(C->getContext()));
  else
    C->replaceAllUsesWith(ConstantInt::getFalse(C->getContext()));
  C->eraseFromParent();

  return true;
}

/// processSwitch - Simplify a switch instruction by removing cases which can
/// never fire.  If the uselessness of a case could be determined locally then
/// constant propagation would already have figured it out.  Instead, walk the
/// predecessors and statically evaluate cases based on information available
/// on that edge.  Cases that cannot fire no matter what the incoming edge can
/// safely be removed.  If a case fires on every incoming edge then the entire
/// switch can be removed and replaced with a branch to the case destination.
bool CorrelatedValuePropagation::processSwitch(SwitchInst *SI) {
  Value *Cond = SI->getCondition();
  BasicBlock *BB = SI->getParent();

  // If the condition was defined in same block as the switch then LazyValueInfo
  // currently won't say anything useful about it, though in theory it could.
  if (isa<Instruction>(Cond) && cast<Instruction>(Cond)->getParent() == BB)
    return false;

  // If the switch is unreachable then trying to improve it is a waste of time.
  pred_iterator PB = pred_begin(BB), PE = pred_end(BB);
  if (PB == PE) return false;

  // Analyse each switch case in turn.  This is done in reverse order so that
  // removing a case doesn't cause trouble for the iteration.
  bool Changed = false;
  for (SwitchInst::CaseIt CI = SI->case_end(), CE = SI->case_begin(); CI-- != CE;
       ) {
    ConstantInt *Case = CI.getCaseValue();

    // Check to see if the switch condition is equal to/not equal to the case
    // value on every incoming edge, equal/not equal being the same each time.
    LazyValueInfo::Tristate State = LazyValueInfo::Unknown;
    for (pred_iterator PI = PB; PI != PE; ++PI) {
      // Is the switch condition equal to the case value?
      LazyValueInfo::Tristate Value = LVI->getPredicateOnEdge(CmpInst::ICMP_EQ,
                                                              Cond, Case, *PI,
                                                              BB, SI);
      // Give up on this case if nothing is known.
      if (Value == LazyValueInfo::Unknown) {
        State = LazyValueInfo::Unknown;
        break;
      }

      // If this was the first edge to be visited, record that all other edges
      // need to give the same result.
      if (PI == PB) {
        State = Value;
        continue;
      }

      // If this case is known to fire for some edges and known not to fire for
      // others then there is nothing we can do - give up.
      if (Value != State) {
        State = LazyValueInfo::Unknown;
        break;
      }
    }

    if (State == LazyValueInfo::False) {
      // This case never fires - remove it.
      CI.getCaseSuccessor()->removePredecessor(BB);
      SI->removeCase(CI); // Does not invalidate the iterator.

      // The condition can be modified by removePredecessor's PHI simplification
      // logic.
      Cond = SI->getCondition();

      ++NumDeadCases;
      Changed = true;
    } else if (State == LazyValueInfo::True) {
      // This case always fires.  Arrange for the switch to be turned into an
      // unconditional branch by replacing the switch condition with the case
      // value.
      SI->setCondition(Case);
      NumDeadCases += SI->getNumCases();
      Changed = true;
      break;
    }
  }

  if (Changed)
    // If the switch has been simplified to the point where it can be replaced
    // by a branch then do so now.
    ConstantFoldTerminator(BB);

  return Changed;
}

/// processCallSite - Infer nonnull attributes for the arguments at the
/// specified callsite.
bool CorrelatedValuePropagation::processCallSite(CallSite CS) {
  SmallVector<unsigned, 4> Indices;
  unsigned ArgNo = 0;

  for (Value *V : CS.args()) {
    PointerType *Type = dyn_cast<PointerType>(V->getType());

    if (Type && !CS.paramHasAttr(ArgNo + 1, Attribute::NonNull) &&
        LVI->getPredicateAt(ICmpInst::ICMP_EQ, V,
                            ConstantPointerNull::get(Type),
                            CS.getInstruction()) == LazyValueInfo::False)
      Indices.push_back(ArgNo + 1);
    ArgNo++;
  }

  assert(ArgNo == CS.arg_size() && "sanity check");

  if (Indices.empty())
    return false;

  AttributeSet AS = CS.getAttributes();
  LLVMContext &Ctx = CS.getInstruction()->getContext();
  AS = AS.addAttribute(Ctx, Indices, Attribute::get(Ctx, Attribute::NonNull));
  CS.setAttributes(AS);

  return true;
}

Constant *CorrelatedValuePropagation::getConstantAt(Value *V, Instruction *At) {
  if (Constant *C = LVI->getConstant(V, At->getParent(), At))
    return C;

  // TODO: The following really should be sunk inside LVI's core algorithm, or
  // at least the outer shims around such.
  auto *C = dyn_cast<CmpInst>(V);
  if (!C) return nullptr;

  Value *Op0 = C->getOperand(0);
  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return nullptr;

  LazyValueInfo::Tristate Result =
    LVI->getPredicateAt(C->getPredicate(), Op0, Op1, At);
  if (Result == LazyValueInfo::Unknown)
    return nullptr;

  return (Result == LazyValueInfo::True) ?
    ConstantInt::getTrue(C->getContext()) :
    ConstantInt::getFalse(C->getContext());
}

bool CorrelatedValuePropagation::runOnFunction(Function &F) {
  if (skipOptnoneFunction(F))
    return false;

  LVI = &getAnalysis<LazyValueInfo>();

  bool FnChanged = false;

  for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
    bool BBChanged = false;
    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *II = &*BI++;
      switch (II->getOpcode()) {
      case Instruction::Select:
        BBChanged |= processSelect(cast<SelectInst>(II));
        break;
      case Instruction::PHI:
        BBChanged |= processPHI(cast<PHINode>(II));
        break;
      case Instruction::ICmp:
      case Instruction::FCmp:
        BBChanged |= processCmp(cast<CmpInst>(II));
        break;
      case Instruction::Load:
      case Instruction::Store:
        BBChanged |= processMemAccess(II);
        break;
      case Instruction::Call:
      case Instruction::Invoke:
        BBChanged |= processCallSite(CallSite(II));
        break;
      }
    }

    Instruction *Term = FI->getTerminator();
    switch (Term->getOpcode()) {
    case Instruction::Switch:
      BBChanged |= processSwitch(cast<SwitchInst>(Term));
      break;
    case Instruction::Ret: {
      auto *RI = cast<ReturnInst>(Term);
      // Try to determine the return value if we can.  This is mainly here to
      // simplify the writing of unit tests, but also helps to enable IPO by
      // constant folding the return values of callees.
      auto *RetVal = RI->getReturnValue();
      if (!RetVal) break; // handle "ret void"
      if (isa<Constant>(RetVal)) break; // nothing to do
      if (auto *C = getConstantAt(RetVal, RI)) {
        ++NumReturns;
        RI->replaceUsesOfWith(RetVal, C);
        BBChanged = true;
      }
    }
    };

    FnChanged |= BBChanged;
  }

  return FnChanged;
}
<commit_msg>Follow up to 260439, Speculative fix to clang builders<commit_after>//===- CorrelatedValuePropagation.cpp - Propagate CFG-derived info --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Correlated Value Propagation pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;

#define DEBUG_TYPE "correlated-value-propagation"

STATISTIC(NumPhis,      "Number of phis propagated");
STATISTIC(NumSelects,   "Number of selects propagated");
STATISTIC(NumMemAccess, "Number of memory access targets propagated");
STATISTIC(NumCmps,      "Number of comparisons propagated");
STATISTIC(NumReturns,   "Number of return values propagated");
STATISTIC(NumDeadCases, "Number of switch cases removed");

namespace {
  class CorrelatedValuePropagation : public FunctionPass {
    LazyValueInfo *LVI;

    bool processSelect(SelectInst *SI);
    bool processPHI(PHINode *P);
    bool processMemAccess(Instruction *I);
    bool processCmp(CmpInst *C);
    bool processSwitch(SwitchInst *SI);
    bool processCallSite(CallSite CS);

    /// Return a constant value for V usable at At and everything it
    /// dominates.  If no such Constant can be found, return nullptr.
    Constant *getConstantAt(Value *V, Instruction *At);

  public:
    static char ID;
    CorrelatedValuePropagation(): FunctionPass(ID) {
     initializeCorrelatedValuePropagationPass(*PassRegistry::getPassRegistry());
    }

    bool runOnFunction(Function &F) override;

    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.addRequired<LazyValueInfo>();
      AU.addPreserved<GlobalsAAWrapperPass>();
    }
  };
}

char CorrelatedValuePropagation::ID = 0;
INITIALIZE_PASS_BEGIN(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)
INITIALIZE_PASS_DEPENDENCY(LazyValueInfo)
INITIALIZE_PASS_END(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)

// Public interface to the Value Propagation pass
Pass *llvm::createCorrelatedValuePropagationPass() {
  return new CorrelatedValuePropagation();
}

bool CorrelatedValuePropagation::processSelect(SelectInst *S) {
  if (S->getType()->isVectorTy()) return false;
  if (isa<Constant>(S->getOperand(0))) return false;

  Constant *C = LVI->getConstant(S->getOperand(0), S->getParent(), S);
  if (!C) return false;

  ConstantInt *CI = dyn_cast<ConstantInt>(C);
  if (!CI) return false;

  Value *ReplaceWith = S->getOperand(1);
  Value *Other = S->getOperand(2);
  if (!CI->isOne()) std::swap(ReplaceWith, Other);
  if (ReplaceWith == S) ReplaceWith = UndefValue::get(S->getType());

  S->replaceAllUsesWith(ReplaceWith);
  S->eraseFromParent();

  ++NumSelects;

  return true;
}

bool CorrelatedValuePropagation::processPHI(PHINode *P) {
  bool Changed = false;

  BasicBlock *BB = P->getParent();
  for (unsigned i = 0, e = P->getNumIncomingValues(); i < e; ++i) {
    Value *Incoming = P->getIncomingValue(i);
    if (isa<Constant>(Incoming)) continue;

    Value *V = LVI->getConstantOnEdge(Incoming, P->getIncomingBlock(i), BB, P);

    // Look if the incoming value is a select with a scalar condition for which
    // LVI can tells us the value. In that case replace the incoming value with
    // the appropriate value of the select. This often allows us to remove the
    // select later.
    if (!V) {
      SelectInst *SI = dyn_cast<SelectInst>(Incoming);
      if (!SI) continue;

      Value *Condition = SI->getCondition();
      if (!Condition->getType()->isVectorTy()) {
        if (Constant *C = LVI->getConstantOnEdge(
                Condition, P->getIncomingBlock(i), BB, P)) {
          if (C->isOneValue()) {
            V = SI->getTrueValue();
          } else if (C->isZeroValue()) {
            V = SI->getFalseValue();
          }
          // Once LVI learns to handle vector types, we could also add support
          // for vector type constants that are not all zeroes or all ones.
        }
      }

      // Look if the select has a constant but LVI tells us that the incoming
      // value can never be that constant. In that case replace the incoming
      // value with the other value of the select. This often allows us to
      // remove the select later.
      if (!V) {
        Constant *C = dyn_cast<Constant>(SI->getFalseValue());
        if (!C) continue;

        if (LVI->getPredicateOnEdge(ICmpInst::ICMP_EQ, SI, C,
              P->getIncomingBlock(i), BB, P) !=
            LazyValueInfo::False)
          continue;
        V = SI->getTrueValue();
      }

      DEBUG(dbgs() << "CVP: Threading PHI over " << *SI << '\n');
    }

    P->setIncomingValue(i, V);
    Changed = true;
  }

  // FIXME: Provide TLI, DT, AT to SimplifyInstruction.
  const DataLayout &DL = BB->getModule()->getDataLayout();
  if (Value *V = SimplifyInstruction(P, DL)) {
    P->replaceAllUsesWith(V);
    P->eraseFromParent();
    Changed = true;
  }

  if (Changed)
    ++NumPhis;

  return Changed;
}

bool CorrelatedValuePropagation::processMemAccess(Instruction *I) {
  Value *Pointer = nullptr;
  if (LoadInst *L = dyn_cast<LoadInst>(I))
    Pointer = L->getPointerOperand();
  else
    Pointer = cast<StoreInst>(I)->getPointerOperand();

  if (isa<Constant>(Pointer)) return false;

  Constant *C = LVI->getConstant(Pointer, I->getParent(), I);
  if (!C) return false;

  ++NumMemAccess;
  I->replaceUsesOfWith(Pointer, C);
  return true;
}

/// processCmp - See if LazyValueInfo's ability to exploit edge conditions,
/// or range information is sufficient to prove this comparison.  Even for
/// local conditions, this can sometimes prove conditions instcombine can't by
/// exploiting range information.
bool CorrelatedValuePropagation::processCmp(CmpInst *C) {
  Value *Op0 = C->getOperand(0);
  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return false;

  // As a policy choice, we choose not to waste compile time on anything where
  // the comparison is testing local values.  While LVI can sometimes reason
  // about such cases, it's not its primary purpose.  We do make sure to do
  // the block local query for uses from terminator instructions, but that's
  // handled in the code for each terminator.
  auto *I = dyn_cast<Instruction>(Op0);
  if (I && I->getParent() == C->getParent())
    return false;

  LazyValueInfo::Tristate Result =
    LVI->getPredicateAt(C->getPredicate(), Op0, Op1, C);
  if (Result == LazyValueInfo::Unknown) return false;

  ++NumCmps;
  if (Result == LazyValueInfo::True)
    C->replaceAllUsesWith(ConstantInt::getTrue(C->getContext()));
  else
    C->replaceAllUsesWith(ConstantInt::getFalse(C->getContext()));
  C->eraseFromParent();

  return true;
}

/// processSwitch - Simplify a switch instruction by removing cases which can
/// never fire.  If the uselessness of a case could be determined locally then
/// constant propagation would already have figured it out.  Instead, walk the
/// predecessors and statically evaluate cases based on information available
/// on that edge.  Cases that cannot fire no matter what the incoming edge can
/// safely be removed.  If a case fires on every incoming edge then the entire
/// switch can be removed and replaced with a branch to the case destination.
bool CorrelatedValuePropagation::processSwitch(SwitchInst *SI) {
  Value *Cond = SI->getCondition();
  BasicBlock *BB = SI->getParent();

  // If the condition was defined in same block as the switch then LazyValueInfo
  // currently won't say anything useful about it, though in theory it could.
  if (isa<Instruction>(Cond) && cast<Instruction>(Cond)->getParent() == BB)
    return false;

  // If the switch is unreachable then trying to improve it is a waste of time.
  pred_iterator PB = pred_begin(BB), PE = pred_end(BB);
  if (PB == PE) return false;

  // Analyse each switch case in turn.  This is done in reverse order so that
  // removing a case doesn't cause trouble for the iteration.
  bool Changed = false;
  for (SwitchInst::CaseIt CI = SI->case_end(), CE = SI->case_begin(); CI-- != CE;
       ) {
    ConstantInt *Case = CI.getCaseValue();

    // Check to see if the switch condition is equal to/not equal to the case
    // value on every incoming edge, equal/not equal being the same each time.
    LazyValueInfo::Tristate State = LazyValueInfo::Unknown;
    for (pred_iterator PI = PB; PI != PE; ++PI) {
      // Is the switch condition equal to the case value?
      LazyValueInfo::Tristate Value = LVI->getPredicateOnEdge(CmpInst::ICMP_EQ,
                                                              Cond, Case, *PI,
                                                              BB, SI);
      // Give up on this case if nothing is known.
      if (Value == LazyValueInfo::Unknown) {
        State = LazyValueInfo::Unknown;
        break;
      }

      // If this was the first edge to be visited, record that all other edges
      // need to give the same result.
      if (PI == PB) {
        State = Value;
        continue;
      }

      // If this case is known to fire for some edges and known not to fire for
      // others then there is nothing we can do - give up.
      if (Value != State) {
        State = LazyValueInfo::Unknown;
        break;
      }
    }

    if (State == LazyValueInfo::False) {
      // This case never fires - remove it.
      CI.getCaseSuccessor()->removePredecessor(BB);
      SI->removeCase(CI); // Does not invalidate the iterator.

      // The condition can be modified by removePredecessor's PHI simplification
      // logic.
      Cond = SI->getCondition();

      ++NumDeadCases;
      Changed = true;
    } else if (State == LazyValueInfo::True) {
      // This case always fires.  Arrange for the switch to be turned into an
      // unconditional branch by replacing the switch condition with the case
      // value.
      SI->setCondition(Case);
      NumDeadCases += SI->getNumCases();
      Changed = true;
      break;
    }
  }

  if (Changed)
    // If the switch has been simplified to the point where it can be replaced
    // by a branch then do so now.
    ConstantFoldTerminator(BB);

  return Changed;
}

/// processCallSite - Infer nonnull attributes for the arguments at the
/// specified callsite.
bool CorrelatedValuePropagation::processCallSite(CallSite CS) {
  SmallVector<unsigned, 4> Indices;
  unsigned ArgNo = 0;

  for (Value *V : CS.args()) {
    PointerType *Type = dyn_cast<PointerType>(V->getType());
    // Try to mark pointer typed parameters as non-null.  We skip the
    // relatively expensive analysis for constants which are obviously either
    // null or non-null to start with.
    if (Type && !CS.paramHasAttr(ArgNo + 1, Attribute::NonNull) &&
        !isa<Constant>(V) &&
        LVI->getPredicateAt(ICmpInst::ICMP_EQ, V,
                            ConstantPointerNull::get(Type),
                            CS.getInstruction()) == LazyValueInfo::False)
      Indices.push_back(ArgNo + 1);
    ArgNo++;
  }

  assert(ArgNo == CS.arg_size() && "sanity check");

  if (Indices.empty())
    return false;

  AttributeSet AS = CS.getAttributes();
  LLVMContext &Ctx = CS.getInstruction()->getContext();
  AS = AS.addAttribute(Ctx, Indices, Attribute::get(Ctx, Attribute::NonNull));
  CS.setAttributes(AS);

  return true;
}

Constant *CorrelatedValuePropagation::getConstantAt(Value *V, Instruction *At) {
  if (Constant *C = LVI->getConstant(V, At->getParent(), At))
    return C;

  // TODO: The following really should be sunk inside LVI's core algorithm, or
  // at least the outer shims around such.
  auto *C = dyn_cast<CmpInst>(V);
  if (!C) return nullptr;

  Value *Op0 = C->getOperand(0);
  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return nullptr;

  LazyValueInfo::Tristate Result =
    LVI->getPredicateAt(C->getPredicate(), Op0, Op1, At);
  if (Result == LazyValueInfo::Unknown)
    return nullptr;

  return (Result == LazyValueInfo::True) ?
    ConstantInt::getTrue(C->getContext()) :
    ConstantInt::getFalse(C->getContext());
}

bool CorrelatedValuePropagation::runOnFunction(Function &F) {
  if (skipOptnoneFunction(F))
    return false;

  LVI = &getAnalysis<LazyValueInfo>();

  bool FnChanged = false;

  for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
    bool BBChanged = false;
    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *II = &*BI++;
      switch (II->getOpcode()) {
      case Instruction::Select:
        BBChanged |= processSelect(cast<SelectInst>(II));
        break;
      case Instruction::PHI:
        BBChanged |= processPHI(cast<PHINode>(II));
        break;
      case Instruction::ICmp:
      case Instruction::FCmp:
        BBChanged |= processCmp(cast<CmpInst>(II));
        break;
      case Instruction::Load:
      case Instruction::Store:
        BBChanged |= processMemAccess(II);
        break;
      case Instruction::Call:
      case Instruction::Invoke:
        BBChanged |= processCallSite(CallSite(II));
        break;
      }
    }

    Instruction *Term = FI->getTerminator();
    switch (Term->getOpcode()) {
    case Instruction::Switch:
      BBChanged |= processSwitch(cast<SwitchInst>(Term));
      break;
    case Instruction::Ret: {
      auto *RI = cast<ReturnInst>(Term);
      // Try to determine the return value if we can.  This is mainly here to
      // simplify the writing of unit tests, but also helps to enable IPO by
      // constant folding the return values of callees.
      auto *RetVal = RI->getReturnValue();
      if (!RetVal) break; // handle "ret void"
      if (isa<Constant>(RetVal)) break; // nothing to do
      if (auto *C = getConstantAt(RetVal, RI)) {
        ++NumReturns;
        RI->replaceUsesOfWith(RetVal, C);
        BBChanged = true;
      }
    }
    };

    FnChanged |= BBChanged;
  }

  return FnChanged;
}
<|endoftext|>


<commit_before>#include <toolbox/testing/test.h>
#include <toolbox/argv/parser.hpp>
#include <toolbox/cpp/make_ref_tuple.hpp>
#include <toolbox/gcc/type_to_string.hpp>
#include <initializer_list>
#include <cstring>

struct cmd_line_options
{
	cmd_line_options(std::initializer_list<const char *> options)
	{
		argc = options.size();
		argv = new char*[options.size()];

		int index = 0;
		for (auto &arg : options) {
			argv[index++] = strdup(arg);
		}
	}

	~cmd_line_options()
	{
		for (int i = 0; i < argc; i++)
			free(argv[i]);
		delete [] argv;
	}

	int argc;
	char **argv;
};

TEST_CASE(argv_basic_parser)
{
	namespace o = toolbox::argv::options;
	int value_from_callback = 0;
	int value_of_number = 0;

	auto verbose = o::option<void>(o::short_name('v'));
	auto opt_a = o::option<void>(o::short_name('a'));
	auto opt_b = o::option<void>(o::short_name('b'));
	auto xes = o::option<void>(o::short_name('x'), o::long_name("longX"));
	auto number = o::option<int>(o::short_name('n')).store(value_of_number);
	auto path = o::option<std::vector<std::string>>(o::short_name('p'));
	auto callback = o::option<int>(o::short_name('c')).action([&value_from_callback](int value) { value_from_callback = value * 2; });

	auto parser = toolbox::argv::make_parser(verbose, number, path, xes, opt_a, opt_b, callback);

	auto args = cmd_line_options(
	{
		"app",
		"arg0",
		"-vv",
		"-xx", "--longX",
		"-ab",
		"-n", "123",
		"-p", "/usr/local",
		"-p", "/var/run",
		"-c", "3",
		"arg1"});
	parser.parse(args.argc, args.argv);

	CHECK(verbose.value() == true);
	CHECK(xes.found() == 3);
	CHECK(number.value() == 123);
	CHECK(value_of_number == 123);
	CHECK(path.value()[0] == "/usr/local");
	CHECK(path.value()[1] == "/var/run");
	CHECK(parser.non_options().size() == 2);
	CHECK(parser.non_options()[0] == "arg0");
	CHECK(parser.non_options()[1] == "arg1");
	CHECK(opt_a.value() == true);
	CHECK(opt_b.value() == true);
	CHECK(value_from_callback == 6);
}
<commit_msg>argv: retab test source file<commit_after>#include <toolbox/testing/test.h>
#include <toolbox/argv/parser.hpp>
#include <toolbox/cpp/make_ref_tuple.hpp>
#include <toolbox/gcc/type_to_string.hpp>
#include <initializer_list>
#include <cstring>

struct cmd_line_options
{
    cmd_line_options(std::initializer_list<const char *> options)
    {
        argc = options.size();
        argv = new char*[options.size()];

        int index = 0;
        for (auto &arg : options) {
            argv[index++] = strdup(arg);
        }
    }

    ~cmd_line_options()
    {
        for (int i = 0; i < argc; i++)
            free(argv[i]);
        delete [] argv;
    }

    int argc;
    char **argv;
};

TEST_CASE(argv_basic_parser)
{
    namespace o = toolbox::argv::options;
    int value_from_callback = 0;
    int value_of_number = 0;

    auto verbose = o::option<void>(o::short_name('v'));
    auto opt_a = o::option<void>(o::short_name('a'));
    auto opt_b = o::option<void>(o::short_name('b'));
    auto xes = o::option<void>(o::short_name('x'), o::long_name("longX"));
    auto number = o::option<int>(o::short_name('n')).store(value_of_number);
    auto path = o::option<std::vector<std::string>>(o::short_name('p'));
    auto callback = o::option<int>(o::short_name('c')).action([&value_from_callback](int value) { value_from_callback = value * 2; });

    auto parser = toolbox::argv::make_parser(verbose, number, path, xes, opt_a, opt_b, callback);

    auto args = cmd_line_options(
    {
        "app",
        "arg0",
        "-vv",
        "-xx", "--longX",
        "-ab",
        "-n", "123",
        "-p", "/usr/local",
        "-p", "/var/run",
        "-c", "3",
        "arg1"});
    parser.parse(args.argc, args.argv);

    CHECK(verbose.value() == true);
    CHECK(xes.found() == 3);
    CHECK(number.value() == 123);
    CHECK(value_of_number == 123);
    CHECK(path.value()[0] == "/usr/local");
    CHECK(path.value()[1] == "/var/run");
    CHECK(parser.non_options().size() == 2);
    CHECK(parser.non_options()[0] == "arg0");
    CHECK(parser.non_options()[1] == "arg1");
    CHECK(opt_a.value() == true);
    CHECK(opt_b.value() == true);
    CHECK(value_from_callback == 6);
}
<|endoftext|>