<commit_before>// Copyright (c) 2009-2018 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// Maintainer: joaander

#include "IntegrationMethodTwoStep.h"
#include "hoomd/VectorMath.h"
#include "QuaternionMath.h"
#include "hoomd/HOOMDMath.h"

#include "hoomd/Saru.h"

namespace py = pybind11;

#ifdef ENABLE_MPI
#include "hoomd/Communicator.h"
#endif

using namespace std;

/*! \file IntegrationMethodTwoStep.h
    \brief Contains code for the IntegrationMethodTwoStep class
*/

/*! \param sysdef SystemDefinition this method will act on. Must not be NULL.
    \param group The group of particles this integration method is to work on
    \post The method is constructed with the given particle data and a NULL profiler.
*/
IntegrationMethodTwoStep::IntegrationMethodTwoStep(std::shared_ptr<SystemDefinition> sysdef,
                                                   std::shared_ptr<ParticleGroup> group)
    : m_sysdef(sysdef), m_group(group), m_pdata(m_sysdef->getParticleData()), m_exec_conf(m_pdata->getExecConf()),
      m_aniso(false), m_deltaT(Scalar(0.0)), m_valid_restart(false)
    {
    // sanity check
    assert(m_sysdef);
    assert(m_pdata);
    assert(m_group);

    m_integrator_id = m_sysdef->getIntegratorData()->registerIntegrator();
    }

/*! It is useful for the user to know where computation time is spent, so all integration methods
    should profile themselves. This method sets the profiler for them to use.
    This method does not need to be called, as Computes will not profile themselves
    on a NULL profiler
    \param prof Pointer to a profiler for the compute to use. Set to NULL
        (std::shared_ptr<Profiler>()) to stop the
        analyzer from profiling itself.
    \note Derived classes MUST check if m_prof is set before calling any profiler methods.
*/
void IntegrationMethodTwoStep::setProfiler(std::shared_ptr<Profiler> prof)
    {
    m_prof = prof;
    }

/*! \param deltaT New time step to set
*/
void IntegrationMethodTwoStep::setDeltaT(Scalar deltaT)
    {
    m_deltaT = deltaT;
    }

/*! \param v is the restart variables for the current integrator
    \param type is the type of expected integrator type
    \param nvariables is the expected number of variables

    If the either the integrator type or number of variables does not match the
    expected values, this function throws the appropriate warning and returns
    "false."  Otherwise, the function returns true.
*/
bool IntegrationMethodTwoStep::restartInfoTestValid(const IntegratorVariables& v, std::string type, unsigned int nvariables)
    {
    bool good = true;
    if (v.type == "")
        good = false;
    else if (v.type != type && v.type != "")
        {
        m_exec_conf->msg->warning() << "Integrator #"<<  m_integrator_id <<" type "<< type <<" does not match type ";
        m_exec_conf->msg->warning() << v.type << " found in restart file. " << endl;
        m_exec_conf->msg->warning() << "Ensure that the integrator order is consistent for restarted simulations. " << endl;
        m_exec_conf->msg->warning() << "Continuing while ignoring restart information..." << endl;
        good = false;
        }
    else if (v.type == type)
        {
        if (v.variable.size() != nvariables)
            {
            m_exec_conf->msg->warning() << "Integrator #"<< m_integrator_id <<" type "<< type << endl;
            m_exec_conf->msg->warning() << "appears to contain bad or incomplete restart information. " << endl;
            m_exec_conf->msg->warning() << "Continuing while ignoring restart information..." << endl;
            good = false;
            }
        }
    return good;
    }

/*! \param query_group Group over which to count (translational) degrees of freedom.
    A majority of the integration methods add D degrees of freedom per particle in \a query_group that is also in the
    group assigned to the method. Hence, the base class IntegrationMethodTwoStep will implement that counting.
    Derived classes can override if needed.
*/
unsigned int IntegrationMethodTwoStep::getNDOF(std::shared_ptr<ParticleGroup> query_group)
    {
    // get the size of the intersection between query_group and m_group
    unsigned int intersect_size = ParticleGroup::groupIntersection(query_group, m_group)->getNumMembersGlobal();

    return m_sysdef->getNDimensions() * intersect_size;
    }

unsigned int IntegrationMethodTwoStep::getRotationalNDOF(std::shared_ptr<ParticleGroup> query_group)
    {
    // get the size of the intersection between query_group and m_group
    std::shared_ptr<ParticleGroup> intersect = ParticleGroup::groupIntersection(query_group, m_group);

    unsigned int local_group_size = intersect->getNumMembers();

    unsigned int query_group_dof = 0;
    unsigned int dimension = m_sysdef->getNDimensions();
    unsigned int dof_one;
    ArrayHandle<Scalar3> h_moment_inertia(m_pdata->getMomentsOfInertiaArray(), access_location::host, access_mode::read);

    for (unsigned int group_idx = 0; group_idx < local_group_size; group_idx++)
        {
        unsigned int j = intersect->getMemberIndex(group_idx);
        if (dimension == 3)
            {
            dof_one = 3;
            if (fabs(h_moment_inertia.data[j].x) < EPSILON)
                dof_one--;

            if (fabs(h_moment_inertia.data[j].y) < EPSILON)
                dof_one--;

            if (fabs(h_moment_inertia.data[j].z) < EPSILON)
                dof_one--;
            }
        else
            {
            dof_one = 1;
            if (fabs(h_moment_inertia.data[j].z) < EPSILON)
                dof_one--;
            }

        query_group_dof += dof_one;
        }

    #ifdef ENABLE_MPI
    if (m_pdata->getDomainDecomposition())
        {
        MPI_Allreduce(MPI_IN_PLACE, &query_group_dof, 1, MPI_UNSIGNED, MPI_SUM, m_exec_conf->getMPICommunicator());
        }
    #endif

    return query_group_dof;
    }

/*! Checks that every particle in the group is valid. This method may be called by anyone wishing to make this
    error check.

    The base class does nothing
*/
void IntegrationMethodTwoStep::validateGroup()
    {
    for (unsigned int gidx = 0; gidx < m_group->getNumMembersGlobal(); gidx++)
        {
        unsigned int tag = m_group->getMemberTag(gidx);
        if (m_pdata->isParticleLocal(tag))
            {
            ArrayHandle<unsigned int> h_body(m_pdata->getBodies(), access_location::host, access_mode::read);
            ArrayHandle<unsigned int> h_rtag(m_pdata->getRTags(), access_location::host, access_mode::read);
            ArrayHandle<unsigned int> h_tag(m_pdata->getTags(), access_location::host, access_mode::read);

            unsigned int body = h_body.data[h_rtag.data[tag]];

            if (body != NO_BODY && body != tag)
                {
                m_exec_conf->msg->error() << "Particle " << tag << " belongs to a rigid body, but is not its center particle. "
                    << std::endl << "This integration method does not operate on constituent particles."
                    << std::endl << std::endl;
                throw std::runtime_error("Error initializing integration method");
                }
            }
        }

    }

/*!
   Randomizes linear velocities and angular momenta by sampling the
   Maxwell-Boltzmann (MB) distribution.
   The user provides three arguments:
   - The particle group
   - Temperature
   - Seed for initializing the random number generator used for this purpose
   These variables are member variables of the class.
*/
void IntegrationMethodTwoStep::randomizeVelocities(unsigned int timestep)
    {
    if (m_shouldRandomize == false)
        {
        return;
        }

    /* Get the number of particles in the group */
    unsigned int group_size = m_group->getNumMembers();

    /* Grab some variables */
    const unsigned int D = Scalar(m_sysdef->getNDimensions());

    ArrayHandle<Scalar4> h_vel(m_pdata->getVelocities(),
                               access_location::host,
                               access_mode::readwrite);

    ArrayHandle<Scalar4> h_orientation(m_pdata->getOrientationArray(),
                                       access_location::host,
                                       access_mode::read);

    ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(),
                                  access_location::host,
                                  access_mode::readwrite);

    ArrayHandle<Scalar3> h_inertia(m_pdata->getMomentsOfInertiaArray(),
                                   access_location::host,
                                   access_mode::read);

    ArrayHandle<unsigned int> h_tag(m_pdata->getTags(),
                                    access_location::host,
                                    access_mode::read);

    /* Total momentum */
    vec3<Scalar> tot_momentum(0, 0, 0);

    /* Loop over all the particles in the group */
    for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
        {
        unsigned int j = m_group->getMemberIndex(group_idx);
        unsigned int ptag = h_tag.data[j];

        /* Initialize the random number generator */
        hoomd::detail::Saru saru(ptag, timestep, m_seed_randomize);

        /* Generate a new random linear velocity for particle j */
        Scalar mass =  h_vel.data[j].w;
        Scalar sigma = fast::sqrt(m_T_randomize / mass);
        h_vel.data[j].x = gaussian_rng(saru, sigma);
        h_vel.data[j].y = gaussian_rng(saru, sigma);
        if (D > 2)
            h_vel.data[j].z = gaussian_rng(saru, sigma);
        else
            h_vel.data[j].z = 0; // For 2D systems

        tot_momentum += mass * vec3<Scalar>(h_vel.data[j]);

        /* Generate a new random angular momentum if the particle is a rigid
         * body and anisotropy flag gets set.
         * There may be some issues for 2D systems */
        if (m_aniso)
            {
            vec3<Scalar> p_vec(0,0,0);
            quat<Scalar> q(h_orientation.data[j]);
            vec3<Scalar> I(h_inertia.data[j]);

            /* Generate a new random angular momentum for particle j in
             * body frame */
            if (I.x >= EPSILON)
                p_vec.x = gaussian_rng(saru, fast::sqrt(m_T_randomize * I.x));
            if (I.y >= EPSILON)
                p_vec.y = gaussian_rng(saru, fast::sqrt(m_T_randomize * I.y));
            if (I.z >= EPSILON)
                p_vec.z = gaussian_rng(saru, fast::sqrt(m_T_randomize * I.z));

            /* Store the angular momentum quaternion */
            quat<Scalar> p = Scalar(2.0) * q * p_vec;
            h_angmom.data[j] = quat_to_scalar4(p);
            }
        }

    /* Remove the drift i.e. remove the center of mass velocity */

    #ifdef ENABLE_MPI
    // Reduce the total momentum from all MPI ranks
    if (m_comm)
       {
       MPI_Allreduce(MPI_IN_PLACE, &tot_momentum, 3, MPI_HOOMD_SCALAR,
                     MPI_SUM, m_exec_conf->getMPICommunicator());
       }
    #endif

    vec3<Scalar> com_momentum(tot_momentum /
                              Scalar(m_group->getNumMembersGlobal()));

    for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
        {
        unsigned int j = m_group->getMemberIndex(group_idx);
        Scalar mass =  h_vel.data[j].w;
        h_vel.data[j].x = h_vel.data[j].x - com_momentum.x / mass;
        h_vel.data[j].y = h_vel.data[j].y - com_momentum.y / mass;
        if (D > 2)
            h_vel.data[j].z = h_vel.data[j].z - com_momentum.z / mass;
        else
            h_vel.data[j].z = 0; // For 2D systems
        }

    /* Done randomizing velocities */

    /* Reset the flag */
    m_shouldRandomize = false;
    }

void export_IntegrationMethodTwoStep(py::module& m)
    {
    py::class_<IntegrationMethodTwoStep, std::shared_ptr<IntegrationMethodTwoStep> >(m, "IntegrationMethodTwoStep")
        .def(py::init< std::shared_ptr<SystemDefinition>, std::shared_ptr<ParticleGroup> >())
        .def("validateGroup", &IntegrationMethodTwoStep::validateGroup)
#ifdef ENABLE_MPI
        .def("setCommunicator", &IntegrationMethodTwoStep::setCommunicator)
#endif
        .def("setRandomizeVelocitiesParams", &IntegrationMethodTwoStep::setRandomizeVelocitiesParams)
        ;
    }
<commit_msg>speed up startup<commit_after>// Copyright (c) 2009-2018 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// Maintainer: joaander

#include "IntegrationMethodTwoStep.h"
#include "hoomd/VectorMath.h"
#include "QuaternionMath.h"
#include "hoomd/HOOMDMath.h"

#include "hoomd/Saru.h"

namespace py = pybind11;

#ifdef ENABLE_MPI
#include "hoomd/Communicator.h"
#endif

using namespace std;

/*! \file IntegrationMethodTwoStep.h
    \brief Contains code for the IntegrationMethodTwoStep class
*/

/*! \param sysdef SystemDefinition this method will act on. Must not be NULL.
    \param group The group of particles this integration method is to work on
    \post The method is constructed with the given particle data and a NULL profiler.
*/
IntegrationMethodTwoStep::IntegrationMethodTwoStep(std::shared_ptr<SystemDefinition> sysdef,
                                                   std::shared_ptr<ParticleGroup> group)
    : m_sysdef(sysdef), m_group(group), m_pdata(m_sysdef->getParticleData()), m_exec_conf(m_pdata->getExecConf()),
      m_aniso(false), m_deltaT(Scalar(0.0)), m_valid_restart(false)
    {
    // sanity check
    assert(m_sysdef);
    assert(m_pdata);
    assert(m_group);

    m_integrator_id = m_sysdef->getIntegratorData()->registerIntegrator();
    }

/*! It is useful for the user to know where computation time is spent, so all integration methods
    should profile themselves. This method sets the profiler for them to use.
    This method does not need to be called, as Computes will not profile themselves
    on a NULL profiler
    \param prof Pointer to a profiler for the compute to use. Set to NULL
        (std::shared_ptr<Profiler>()) to stop the
        analyzer from profiling itself.
    \note Derived classes MUST check if m_prof is set before calling any profiler methods.
*/
void IntegrationMethodTwoStep::setProfiler(std::shared_ptr<Profiler> prof)
    {
    m_prof = prof;
    }

/*! \param deltaT New time step to set
*/
void IntegrationMethodTwoStep::setDeltaT(Scalar deltaT)
    {
    m_deltaT = deltaT;
    }

/*! \param v is the restart variables for the current integrator
    \param type is the type of expected integrator type
    \param nvariables is the expected number of variables

    If the either the integrator type or number of variables does not match the
    expected values, this function throws the appropriate warning and returns
    "false."  Otherwise, the function returns true.
*/
bool IntegrationMethodTwoStep::restartInfoTestValid(const IntegratorVariables& v, std::string type, unsigned int nvariables)
    {
    bool good = true;
    if (v.type == "")
        good = false;
    else if (v.type != type && v.type != "")
        {
        m_exec_conf->msg->warning() << "Integrator #"<<  m_integrator_id <<" type "<< type <<" does not match type ";
        m_exec_conf->msg->warning() << v.type << " found in restart file. " << endl;
        m_exec_conf->msg->warning() << "Ensure that the integrator order is consistent for restarted simulations. " << endl;
        m_exec_conf->msg->warning() << "Continuing while ignoring restart information..." << endl;
        good = false;
        }
    else if (v.type == type)
        {
        if (v.variable.size() != nvariables)
            {
            m_exec_conf->msg->warning() << "Integrator #"<< m_integrator_id <<" type "<< type << endl;
            m_exec_conf->msg->warning() << "appears to contain bad or incomplete restart information. " << endl;
            m_exec_conf->msg->warning() << "Continuing while ignoring restart information..." << endl;
            good = false;
            }
        }
    return good;
    }

/*! \param query_group Group over which to count (translational) degrees of freedom.
    A majority of the integration methods add D degrees of freedom per particle in \a query_group that is also in the
    group assigned to the method. Hence, the base class IntegrationMethodTwoStep will implement that counting.
    Derived classes can override if needed.
*/
unsigned int IntegrationMethodTwoStep::getNDOF(std::shared_ptr<ParticleGroup> query_group)
    {
    // get the size of the intersection between query_group and m_group
    unsigned int intersect_size = ParticleGroup::groupIntersection(query_group, m_group)->getNumMembersGlobal();

    return m_sysdef->getNDimensions() * intersect_size;
    }

unsigned int IntegrationMethodTwoStep::getRotationalNDOF(std::shared_ptr<ParticleGroup> query_group)
    {
    // get the size of the intersection between query_group and m_group
    std::shared_ptr<ParticleGroup> intersect = ParticleGroup::groupIntersection(query_group, m_group);

    unsigned int local_group_size = intersect->getNumMembers();

    unsigned int query_group_dof = 0;
    unsigned int dimension = m_sysdef->getNDimensions();
    unsigned int dof_one;
    ArrayHandle<Scalar3> h_moment_inertia(m_pdata->getMomentsOfInertiaArray(), access_location::host, access_mode::read);

    for (unsigned int group_idx = 0; group_idx < local_group_size; group_idx++)
        {
        unsigned int j = intersect->getMemberIndex(group_idx);
        if (dimension == 3)
            {
            dof_one = 3;
            if (fabs(h_moment_inertia.data[j].x) < EPSILON)
                dof_one--;

            if (fabs(h_moment_inertia.data[j].y) < EPSILON)
                dof_one--;

            if (fabs(h_moment_inertia.data[j].z) < EPSILON)
                dof_one--;
            }
        else
            {
            dof_one = 1;
            if (fabs(h_moment_inertia.data[j].z) < EPSILON)
                dof_one--;
            }

        query_group_dof += dof_one;
        }

    #ifdef ENABLE_MPI
    if (m_pdata->getDomainDecomposition())
        {
        MPI_Allreduce(MPI_IN_PLACE, &query_group_dof, 1, MPI_UNSIGNED, MPI_SUM, m_exec_conf->getMPICommunicator());
        }
    #endif

    return query_group_dof;
    }

/*! Checks that every particle in the group is valid. This method may be called by anyone wishing to make this
    error check.

    The base class does nothing
*/
void IntegrationMethodTwoStep::validateGroup()
    {
    ArrayHandle<unsigned int> h_body(m_pdata->getBodies(), access_location::host, access_mode::read);
    ArrayHandle<unsigned int> h_rtag(m_pdata->getRTags(), access_location::host, access_mode::read);
    ArrayHandle<unsigned int> h_tag(m_pdata->getTags(), access_location::host, access_mode::read);
    ArrayHandle<unsigned int> h_group_index(m_group->getIndexArray(), access_location::host, access_mode::read);

    for (unsigned int gidx = 0; gidx < m_group->getNumMembers(); gidx++)
        {
        unsigned int i = h_group_index.data[gidx];
        unsigned int tag = h_tag.data[i];
        unsigned int body = h_body.data[i];

        if (body != NO_BODY && body != tag)
            {
            m_exec_conf->msg->error() << "Particle " << tag << " belongs to a rigid body, but is not its center particle. "
                << std::endl << "This integration method does not operate on constituent particles."
                << std::endl << std::endl;
            throw std::runtime_error("Error initializing integration method");
            }
        }

    }

/*!
   Randomizes linear velocities and angular momenta by sampling the
   Maxwell-Boltzmann (MB) distribution.
   The user provides three arguments:
   - The particle group
   - Temperature
   - Seed for initializing the random number generator used for this purpose
   These variables are member variables of the class.
*/
void IntegrationMethodTwoStep::randomizeVelocities(unsigned int timestep)
    {
    if (m_shouldRandomize == false)
        {
        return;
        }

    /* Get the number of particles in the group */
    unsigned int group_size = m_group->getNumMembers();

    /* Grab some variables */
    const unsigned int D = Scalar(m_sysdef->getNDimensions());

    ArrayHandle<Scalar4> h_vel(m_pdata->getVelocities(),
                               access_location::host,
                               access_mode::readwrite);

    ArrayHandle<Scalar4> h_orientation(m_pdata->getOrientationArray(),
                                       access_location::host,
                                       access_mode::read);

    ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(),
                                  access_location::host,
                                  access_mode::readwrite);

    ArrayHandle<Scalar3> h_inertia(m_pdata->getMomentsOfInertiaArray(),
                                   access_location::host,
                                   access_mode::read);

    ArrayHandle<unsigned int> h_tag(m_pdata->getTags(),
                                    access_location::host,
                                    access_mode::read);

    /* Total momentum */
    vec3<Scalar> tot_momentum(0, 0, 0);

    /* Loop over all the particles in the group */
    for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
        {
        unsigned int j = m_group->getMemberIndex(group_idx);
        unsigned int ptag = h_tag.data[j];

        /* Initialize the random number generator */
        hoomd::detail::Saru saru(ptag, timestep, m_seed_randomize);

        /* Generate a new random linear velocity for particle j */
        Scalar mass =  h_vel.data[j].w;
        Scalar sigma = fast::sqrt(m_T_randomize / mass);
        h_vel.data[j].x = gaussian_rng(saru, sigma);
        h_vel.data[j].y = gaussian_rng(saru, sigma);
        if (D > 2)
            h_vel.data[j].z = gaussian_rng(saru, sigma);
        else
            h_vel.data[j].z = 0; // For 2D systems

        tot_momentum += mass * vec3<Scalar>(h_vel.data[j]);

        /* Generate a new random angular momentum if the particle is a rigid
         * body and anisotropy flag gets set.
         * There may be some issues for 2D systems */
        if (m_aniso)
            {
            vec3<Scalar> p_vec(0,0,0);
            quat<Scalar> q(h_orientation.data[j]);
            vec3<Scalar> I(h_inertia.data[j]);

            /* Generate a new random angular momentum for particle j in
             * body frame */
            if (I.x >= EPSILON)
                p_vec.x = gaussian_rng(saru, fast::sqrt(m_T_randomize * I.x));
            if (I.y >= EPSILON)
                p_vec.y = gaussian_rng(saru, fast::sqrt(m_T_randomize * I.y));
            if (I.z >= EPSILON)
                p_vec.z = gaussian_rng(saru, fast::sqrt(m_T_randomize * I.z));

            /* Store the angular momentum quaternion */
            quat<Scalar> p = Scalar(2.0) * q * p_vec;
            h_angmom.data[j] = quat_to_scalar4(p);
            }
        }

    /* Remove the drift i.e. remove the center of mass velocity */

    #ifdef ENABLE_MPI
    // Reduce the total momentum from all MPI ranks
    if (m_comm)
       {
       MPI_Allreduce(MPI_IN_PLACE, &tot_momentum, 3, MPI_HOOMD_SCALAR,
                     MPI_SUM, m_exec_conf->getMPICommunicator());
       }
    #endif

    vec3<Scalar> com_momentum(tot_momentum /
                              Scalar(m_group->getNumMembersGlobal()));

    for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
        {
        unsigned int j = m_group->getMemberIndex(group_idx);
        Scalar mass =  h_vel.data[j].w;
        h_vel.data[j].x = h_vel.data[j].x - com_momentum.x / mass;
        h_vel.data[j].y = h_vel.data[j].y - com_momentum.y / mass;
        if (D > 2)
            h_vel.data[j].z = h_vel.data[j].z - com_momentum.z / mass;
        else
            h_vel.data[j].z = 0; // For 2D systems
        }

    /* Done randomizing velocities */

    /* Reset the flag */
    m_shouldRandomize = false;
    }

void export_IntegrationMethodTwoStep(py::module& m)
    {
    py::class_<IntegrationMethodTwoStep, std::shared_ptr<IntegrationMethodTwoStep> >(m, "IntegrationMethodTwoStep")
        .def(py::init< std::shared_ptr<SystemDefinition>, std::shared_ptr<ParticleGroup> >())
        .def("validateGroup", &IntegrationMethodTwoStep::validateGroup)
#ifdef ENABLE_MPI
        .def("setCommunicator", &IntegrationMethodTwoStep::setCommunicator)
#endif
        .def("setRandomizeVelocitiesParams", &IntegrationMethodTwoStep::setRandomizeVelocitiesParams)
        ;
    }
<|endoftext|>


<commit_before>/*****************************************************************************
******************************************************************************

bmpgrep

Author: Gordon McCreight
email: gordon@mccreight.com

date modified: 2009-04-25
version: 0.08

License: GPL 2
Copyright: 2009 by Gordon McCreight

usage:
  bmpgrep return_how_many_matches pattern_threshold (the line continues...)
    tolerance_r tolerance_g tolerance_b big.bmp small.bmp

If return_how_many_matches is set to 0, then it will find as many as it can.

"pattern_threshold" determines how aggressively it tries to shrink the pattern
it creates for the small image.  We recommend something around 30.  A value of
0 skips no pixels.  Over 100 tends to cause false positive matches, because
there may not be enough pixels to check.

tolerances are 0-255

description: Find the location of a small BMP within a big one.
Prints a comma seperated list of x,y (for one match)
or x,y,x,y,x,y for multiple matches.

Note: Can be compiled like so:
g++ -o bmpgrep bmpgrep.cpp EasyBMP.cpp

After you compile, you might want to test with this (the result should be
six numbers long):
./bmpgrep 0 30 0 0 0 test_images/big.bmp test_images/small.bmp

The program also ships with a compile_and_test.pl perl script that
pushes the tests a bit harder.  You can also run that test script
with the option 1 ( so, like ./compile_and_test.pl 1 ) and it will
run it as a performance test.

One note, we modify the stock EasyBMP library in one place where is does
bounds checking on the pixel requested.  We've removed the bounds checking.
This speeds things up a bit.

TODO: Better options verification and add help information.
******************************************************************************
*****************************************************************************/

#include "EasyBMP.h"
using namespace std;

// This needs to be created as a global because it potentially needs to be
// really big.  Arrays allocated inside a function cannot be this big.
int fast_pattern[800 * 600][5];

static inline double Abs (double Nbr) {
    if( Nbr >= 0 )
        return Nbr;
    else
        return -Nbr;
}

int main( int argc, char* argv[] ) {

    int optind = 1;

    int return_how_many_matches = atoi(argv[ optind ]);
    optind++;

    int pattern_threshold = atoi(argv[ optind ]);
    optind++;

    int tolerance_r = atoi(argv[ optind ]);
    optind++;

    int tolerance_g = atoi(argv[ optind ]);
    optind++;

    int tolerance_b = atoi(argv[ optind ]);
    optind++;

    int has_tolerances = false;
    if (tolerance_r > 0 || tolerance_g > 0 || tolerance_b > 0) {
        has_tolerances = true;
    }

    BMP Big;
    Big.ReadFromFile(argv[ optind ]);
    optind++;

    BMP Small;
    Small.ReadFromFile(argv[ optind ]);
    optind++;

    int big_x, big_y, small_x, small_y;

    int big_height = Big.TellHeight();
    int big_width = Big.TellWidth();
    int small_height = Small.TellHeight();
    int small_width = Small.TellWidth();

    if ( small_height * small_width > 800 * 600 ) {
        cout << "We can only handle small images that contain fewer than"
          << "800 x 600 pixels" << endl;
        return 0;
    }

    int small_pattern_array_size = 0;
    int last_pattern_pixel_brightness = -1;
    for (small_y = 0; small_y < small_height; small_y++) {
        for (small_x = 0; small_x < small_width; small_x++) {
            RGBApixel* SmallPixel = Small(small_x, small_y);
            int this_pixel_brightness = SmallPixel->Red
              + SmallPixel->Green + SmallPixel->Blue;
            if ( Abs( this_pixel_brightness - last_pattern_pixel_brightness )
              >= pattern_threshold ) {
                fast_pattern[small_pattern_array_size][0] = small_x;
                fast_pattern[small_pattern_array_size][1] = small_y;
                fast_pattern[small_pattern_array_size][2] = SmallPixel->Red;
                fast_pattern[small_pattern_array_size][3] = SmallPixel->Green;
                fast_pattern[small_pattern_array_size][4] = SmallPixel->Blue;

                last_pattern_pixel_brightness = this_pixel_brightness;
                small_pattern_array_size++;
            }
        }
    }

    //#define DEBUG_THE_FAST_PATTERN
    #ifdef DEBUG_THE_FAST_PATTERN
    for ( int pattern_index = 0; pattern_index < 5; pattern_index++ ) {
        for ( int part = 0; part < 5; part++ ) {
            cout << fast_pattern[pattern_index][part] << endl;
        }
        cout << endl;
    }
    cout << small_pattern_array_size << endl;
    return 0;
    #endif

    /*
    You don't need to check the whole big image.
    For example, if the small image is 100 pixels wide, then you
    know that there's no way it could match in the 99 right-most
    pixels of the big image.  The same idea is applicable for the height.
    */

    int max_y_to_check = big_height - small_height;
    int max_x_to_check = big_width - small_width;

    int has_written_results = 0;
    int has_matched_x_times = 0;

    /*
    This is declared here instead of inside the inner "pattern" for loop
    because we use it after the for loop is completed to check if there
    was a perfect match
    */
    int small_pattern_index = 0;

    for (big_y = 0; big_y < max_y_to_check; ++big_y) {
        for (big_x = 0; big_x < max_x_to_check; ++big_x) {

            for ( small_pattern_index = 0;
                small_pattern_index < small_pattern_array_size;
                small_pattern_index++ ) {

                RGBApixel* BigPixel = Big(big_x + fast_pattern[small_pattern_index][0],
                               big_y + fast_pattern[small_pattern_index][1]);

                /*
                Do these as preprocessor macros for two reasons.
                The first is that they're used in two places, and
                the code looks a lot cleaner.
                The second is that it's better than writing them
                to variables, since they may not all three be used
                in each comparison, and variables are overkill anyhow.
                */
                #define SMALL_RED fast_pattern[small_pattern_index][2]
                #define SMALL_GREEN fast_pattern[small_pattern_index][3]
                #define SMALL_BLUE fast_pattern[small_pattern_index][4]

                if ( has_tolerances == false ) {
                    // zero tolerance, so do it faster
                    if ( BigPixel->Red != SMALL_RED ) {
                        break;
                    }
                    else if ( BigPixel->Green != SMALL_GREEN ) {
                        break;
                    }
                    else if ( BigPixel->Blue != SMALL_BLUE ) {
                        break;
                    }
                }
                else {
                    if ( Abs(BigPixel->Red - SMALL_RED )
                        > tolerance_r ) {
                        break;
                    }
                    else if ( Abs(BigPixel->Green - SMALL_GREEN )
                        > tolerance_g ) {
                        break;
                    }
                    else if ( Abs(BigPixel->Blue - SMALL_BLUE )
                        > tolerance_b ) {
                        break;
                    }
                }
            }

            // There was a complete match!  Note that this check
            // is done after the for loop, not inside it.  Checking
            // outside the loop is a bit faster.
            if (small_pattern_index == small_pattern_array_size) {
              if (has_written_results == 1) {
                cout << ",";
              }
              cout << big_x << "," << big_y;
              has_matched_x_times++;

              if (has_matched_x_times == return_how_many_matches) {
                  cout << endl;
                  return 0;
              }

              has_written_results = 1;
            }
        }
    }

    if (has_written_results == 1) {
        cout << endl;
    }

    return 0;

}
<commit_msg>committing so I can revert but keep this version<commit_after>/*****************************************************************************
******************************************************************************

bmpgrep

Author: Gordon McCreight
email: gordon@mccreight.com

date modified: 2009-04-27
version: 0.09

License: GPL 2
Copyright: 2009 by Gordon McCreight

usage:
  bmpgrep return_how_many_matches pattern_threshold (the line continues...)
    tolerance_r tolerance_g tolerance_b big.bmp small.bmp

If return_how_many_matches is set to 0, then it will find as many as it can.

"pattern_threshold" determines how aggressively it tries to shrink the pattern
it creates for the small image.  We recommend something around 30.  A value of
0 skips no pixels.  Over 100 tends to cause false positive matches, because
there may not be enough pixels to check.

tolerances are 0-255

description: Find the location of a small BMP within a big one.
Prints a comma seperated list of x,y (for one match)
or x,y,x,y,x,y for multiple matches.

Note: Can be compiled like so:
g++ -o bmpgrep bmpgrep.cpp EasyBMP.cpp

After you compile, you might want to test with this (the result should be
six numbers long):
./bmpgrep 0 30 0 0 0 test_images/big.bmp test_images/small.bmp

The program also ships with a compile_and_test.pl perl script that
pushes the tests a bit harder.  You can also run that test script
with the option 1 ( so, like ./compile_and_test.pl 1 ) and it will
run it as a performance test.

One note, we modify the stock EasyBMP library in one place where is does
bounds checking on the pixel requested.  We've removed the bounds checking.
This speeds things up a bit.

TODO: Better options verification and add help information.
******************************************************************************
*****************************************************************************/

#include "EasyBMP.h"
using namespace std;

// This needs to be created as a global because it potentially needs to be
// really big.  Arrays allocated inside a function cannot be this big.
int fast_pattern[800 * 600][5];

static inline double Abs (double Nbr) {
    if( Nbr >= 0 )
        return Nbr;
    else
        return -Nbr;
}

int main( int argc, char* argv[] ) {

    int optind = 1;

    int return_how_many_matches = atoi(argv[ optind ]);
    optind++;

    int pattern_threshold = atoi(argv[ optind ]);
    optind++;

    int tolerance_r = atoi(argv[ optind ]);
    optind++;

    int tolerance_g = atoi(argv[ optind ]);
    optind++;

    int tolerance_b = atoi(argv[ optind ]);
    optind++;

    int has_tolerances = false;
    if (tolerance_r > 0 || tolerance_g > 0 || tolerance_b > 0) {
        has_tolerances = true;
    }

    BMP Big;
    Big.ReadFromFile(argv[ optind ]);
    optind++;

    BMP Small;
    Small.ReadFromFile(argv[ optind ]);
    optind++;

    int big_x, big_y, small_x, small_y;

    int big_height = Big.TellHeight();
    int big_width = Big.TellWidth();
    int small_height = Small.TellHeight();
    int small_width = Small.TellWidth();

    if ( small_height * small_width > 800 * 600 ) {
        cout << "We can only handle small images that contain fewer than"
          << "800 x 600 pixels" << endl;
        return 0;
    }

    int small_pattern_array_size = 0;
    int last_pattern_pixel_brightness = -1;
    for (small_y = 0; small_y < small_height; small_y++) {
        for (small_x = 0; small_x < small_width; small_x++) {
            RGBApixel* SmallPixel = Small(small_x, small_y);
            int this_pixel_brightness = SmallPixel->Red
              + SmallPixel->Green + SmallPixel->Blue;
            if ( Abs( this_pixel_brightness - last_pattern_pixel_brightness )
              >= pattern_threshold ) {
                fast_pattern[small_pattern_array_size][0] = small_x;
                fast_pattern[small_pattern_array_size][1] = small_y;
                fast_pattern[small_pattern_array_size][2] = SmallPixel->Red;
                fast_pattern[small_pattern_array_size][3] = SmallPixel->Green;
                fast_pattern[small_pattern_array_size][4] = SmallPixel->Blue;

                last_pattern_pixel_brightness = this_pixel_brightness;
                small_pattern_array_size++;
            }
        }
    }

    //#define DEBUG_THE_FAST_PATTERN
    #ifdef DEBUG_THE_FAST_PATTERN
    for ( int pattern_index = 0; pattern_index < 5; pattern_index++ ) {
        for ( int part = 0; part < 5; part++ ) {
            cout << fast_pattern[pattern_index][part] << endl;
        }
        cout << endl;
    }
    cout << small_pattern_array_size << endl;
    return 0;
    #endif

    /*
    You don't need to check the whole big image.
    For example, if the small image is 100 pixels wide, then you
    know that there's no way it could match in the 99 right-most
    pixels of the big image.  The same idea is applicable for the height.
    */

    int max_y_to_check = big_height - small_height;
    int max_x_to_check = big_width - small_width;

    int has_written_results = 0;
    int has_matched_x_times = 0;

    /*
    This is declared here instead of inside the inner "pattern" for loop
    because we use it after the for loop is completed to check if there
    was a perfect match
    */
    int small_pattern_index = 0;

    /*
    LOOPS_START and LOOPS_END are done as preprocessor macros because
    of the difference between has_tolerances == true and
    has_tolerances == false.  I used to check whether
    has_tolerances == false inside the inner loop, but that would be
    checked potentially millions of times for even a smaller "big"
    image.  So, I decided to move the check to the outside of the
    loop.  But that meant we had to have the exact same set of source
    code for the loop in two places.  Ugly.  So I consolidated it into
    these two preprocessor definitions.  Still not too pretty, but DRY.

    In the previous version, the fastest run was 6.57
    */

    #define LOOPS_START \
      for (big_y = 0; big_y < max_y_to_check; big_y++) { \
          for (big_x = 0; big_x < max_x_to_check; big_x++) { \
              for ( small_pattern_index = 0; \
                small_pattern_index < small_pattern_array_size; \
                small_pattern_index++ ) { \
                RGBApixel* BigPixel = Big(big_x + fast_pattern[small_pattern_index][0], \
                               big_y + fast_pattern[small_pattern_index][1]);

    #define LOOPS_END \
            } \
            if (small_pattern_index == small_pattern_array_size) { \
              if (has_written_results == 1) { \
                cout << ","; \
              } \
              cout << big_x << "," << big_y; \
              has_matched_x_times++; \
              if (has_matched_x_times == return_how_many_matches) { \
                  cout << endl; \
                  return 0; \
              } \
              has_written_results = 1; \
            } \
        } \
    } \

    /*
    These three are preprocessor macros for two reasons.
    The first is that they're used in two places, and
    the code looks a lot cleaner.
    The second is that it's better than writing them
    to variables, since they may not all three be used
    in each comparison, and variables are overkill.
    */
    #define SMALL_RED fast_pattern[small_pattern_index][2]
    #define SMALL_GREEN fast_pattern[small_pattern_index][3]
    #define SMALL_BLUE fast_pattern[small_pattern_index][4]

    if ( has_tolerances == false ) {
        LOOPS_START
            // zero tolerance, so do it faster
            if ( BigPixel->Red != SMALL_RED ) {
                break;
            }
            else if ( BigPixel->Green != SMALL_GREEN ) {
                break;
            }
            else if ( BigPixel->Blue != SMALL_BLUE ) {
                break;
            }
        LOOPS_END
    }
    else {
        LOOPS_START
            if ( Abs(BigPixel->Red - SMALL_RED )
                > tolerance_r ) {
                break;
            }
            else if ( Abs(BigPixel->Green - SMALL_GREEN )
                > tolerance_g ) {
                break;
            }
            else if ( Abs(BigPixel->Blue - SMALL_BLUE )
                > tolerance_b ) {
                break;
            }
        LOOPS_END
    }

    if (has_written_results == 1) {
        cout << endl;
    }

    return 0;

}
<|endoftext|>


<commit_before>#include <sstream>

#include "StorageFlattening.h"
#include "IRMutator.h"
#include "IROperator.h"
#include "Scope.h"
#include "Bounds.h"
#include "Parameter.h"

namespace Halide {
namespace Internal {

using std::ostringstream;
using std::string;
using std::vector;
using std::map;
using std::pair;
using std::set;

namespace {

class FlattenDimensions : public IRMutator {
public:
    FlattenDimensions(const map<string, pair<Function, int>> &e, const Target &t)
        : env(e), target(t) {}
    Scope<int> scope;
private:
    const map<string, pair<Function, int>> &env;
    const Target ⌖
    Scope<int> realizations;

    Expr flatten_args(const string &name, const vector<Expr> &args) {
        bool internal = realizations.contains(name);
        Expr idx = target.has_feature(Target::LargeBuffers) ? make_zero(Int(64)) : 0;
        vector<Expr> mins(args.size()), strides(args.size());

        for (size_t i = 0; i < args.size(); i++) {
            string dim = std::to_string(i);
            string stride_name = name + ".stride." + dim;
            string min_name = name + ".min." + dim;
            string stride_name_constrained = stride_name + ".constrained";
            string min_name_constrained = min_name + ".constrained";
            if (scope.contains(stride_name_constrained)) {
                stride_name = stride_name_constrained;
            }
            if (scope.contains(min_name_constrained)) {
                min_name = min_name_constrained;
            }
            strides[i] = Variable::make(Int(32), stride_name);
            mins[i] = Variable::make(Int(32), min_name);
        }

        if (internal) {
            // f(x, y) -> f[(x-xmin)*xstride + (y-ymin)*ystride] This
            // strategy makes sense when we expect x to cancel with
            // something in xmin.  We use this for internal allocations
            for (size_t i = 0; i < args.size(); i++) {
                if (target.has_feature(Target::LargeBuffers)) {
                    idx += cast<int64_t>(args[i] - mins[i]) * cast<int64_t>(strides[i]);
                } else {
                    idx += (args[i] - mins[i]) * strides[i];
                }
            }
        } else {
            // f(x, y) -> f[x*stride + y*ystride - (xstride*xmin +
            // ystride*ymin)]. The idea here is that the last term
            // will be pulled outside the inner loop. We use this for
            // external buffers, where the mins and strides are likely
            // to be symbolic
            Expr base = target.has_feature(Target::LargeBuffers) ? make_zero(Int(64)) : 0;
            for (size_t i = 0; i < args.size(); i++) {
                if (target.has_feature(Target::LargeBuffers)) {
                    idx += cast<int64_t>(args[i]) * cast<int64_t>(strides[i]);
                    base += cast<int64_t>(mins[i]) * cast<int64_t>(strides[i]);
                } else {
                    idx += args[i] * strides[i];
                    base += mins[i] * strides[i];
                }
            }
            idx -= base;
        }

        return idx;
    }

    using IRMutator::visit;

    void visit(const Realize *op) {
        realizations.push(op->name, 0);

        Stmt body = mutate(op->body);

        // Compute the size
        std::vector<Expr> extents;
        for (size_t i = 0; i < op->bounds.size(); i++) {
            extents.push_back(op->bounds[i].extent);
            extents[i] = mutate(extents[i]);
        }
        Expr condition = mutate(op->condition);

        realizations.pop(op->name);

        vector<int> storage_permutation;
        {
            auto iter = env.find(op->name);
            Function f = iter->second.first;
            internal_assert(iter != env.end()) << "Realize node refers to function not in environment.\n";
            const vector<StorageDim> &storage_dims = f.schedule().storage_dims();
            const vector<string> &args = f.args();
            for (size_t i = 0; i < storage_dims.size(); i++) {
                for (size_t j = 0; j < args.size(); j++) {
                    if (args[j] == storage_dims[i].var) {
                        storage_permutation.push_back((int)j);
                        Expr alignment = storage_dims[i].alignment;
                        if (alignment.defined()) {
                            extents[j] = ((extents[j] + alignment - 1)/alignment)*alignment;
                        }
                    }
                }
                internal_assert(storage_permutation.size() == i+1);
            }
        }

        internal_assert(storage_permutation.size() == op->bounds.size());

        stmt = body;
        internal_assert(op->types.size() == 1);

        // Make the names for the mins, extents, and strides
        int dims = op->bounds.size();
        vector<string> min_name(dims), extent_name(dims), stride_name(dims);
        for (int i = 0; i < dims; i++) {
            string d = std::to_string(i);
            min_name[i] = op->name + ".min." + d;
            stride_name[i] = op->name + ".stride." + d;
            extent_name[i] = op->name + ".extent." + d;
        }
        vector<Expr> min_var(dims), extent_var(dims), stride_var(dims);
        for (int i = 0; i < dims; i++) {
            min_var[i] = Variable::make(Int(32), min_name[i]);
            extent_var[i] = Variable::make(Int(32), extent_name[i]);
            stride_var[i] = Variable::make(Int(32), stride_name[i]);
        }

        // Create a buffer_t object for this allocation.
        if (dims <= 4) {
            BufferBuilder builder;
            Expr first_elem = Load::make(op->types[0], op->name, 0, Buffer<>(), Parameter(),
                                         const_true(op->types[0].lanes()));
            builder.host = Call::make(Handle(), Call::address_of, {first_elem}, Call::PureIntrinsic);
            builder.type = op->types[0];
            builder.dimensions = dims;
            for (int i = 0; i < dims; i++) {
                builder.mins.push_back(min_var[i]);
                builder.extents.push_back(extent_var[i]);
                builder.strides.push_back(stride_var[i]);
            }
            stmt = LetStmt::make(op->name + ".buffer", builder.build(), stmt);
        }

        // Make the allocation node
        stmt = Allocate::make(op->name, op->types[0], extents, condition, stmt);

        // Compute the strides
        for (int i = (int)op->bounds.size()-1; i > 0; i--) {
            int prev_j = storage_permutation[i-1];
            int j = storage_permutation[i];
            Expr stride = stride_var[prev_j] * extent_var[prev_j];
            stmt = LetStmt::make(stride_name[j], stride, stmt);
        }

        // Innermost stride is one
        if (dims > 0) {
            int innermost = storage_permutation.empty() ? 0 : storage_permutation[0];
            stmt = LetStmt::make(stride_name[innermost], 1, stmt);
        }

        // Assign the mins and extents stored
        for (size_t i = op->bounds.size(); i > 0; i--) {
            stmt = LetStmt::make(min_name[i-1], op->bounds[i-1].min, stmt);
            stmt = LetStmt::make(extent_name[i-1], extents[i-1], stmt);
        }
    }

    void visit(const Provide *op) {
        internal_assert(op->values.size() == 1);

        Expr idx = mutate(flatten_args(op->name, op->args));
        Expr value = mutate(op->values[0]);
        stmt = Store::make(op->name, value, idx, Parameter(), const_true(value.type().lanes()));
    }

    void visit(const Call *op) {
        if (op->call_type == Call::Halide ||
            op->call_type == Call::Image) {
            internal_assert(op->value_index == 0);
            Expr idx = mutate(flatten_args(op->name, op->args));
            expr = Load::make(op->type, op->name, idx, op->image, op->param,
                              const_true(op->type.lanes()));
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const LetStmt *let) {
        // Discover constrained versions of things.
        bool constrained_version_exists = ends_with(let->name, ".constrained");
        if (constrained_version_exists) {
            scope.push(let->name, 0);
        }

        IRMutator::visit(let);

        if (constrained_version_exists) {
            scope.pop(let->name);
        }
    }
};

// Realizations, stores, and loads must all be on types that are
// multiples of 8-bits. This really only affects bools
class PromoteToMemoryType : public IRMutator {
    using IRMutator::visit;

    Type upgrade(Type t) {
        return t.with_bits(((t.bits() + 7)/8)*8);
    }

    void visit(const Call *op) {
        if (op->is_intrinsic(Call::address_of)) {
            Expr load = mutate(op->args[0]);
            if (const Cast *cast = load.as<Cast>()) {
                load = cast->value;
            }
            expr = Call::make(op->type, op->name, {load}, op->call_type);
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Load *op) {
        Type t = upgrade(op->type);
        if (t != op->type) {
            expr = Cast::make(op->type, Load::make(t, op->name, mutate(op->index),
                                                   op->image, op->param, mutate(op->predicate)));
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Store *op) {
        Type t = upgrade(op->value.type());
        if (t != op->value.type()) {
            stmt = Store::make(op->name, Cast::make(t, mutate(op->value)), mutate(op->index),
                                                    op->param, mutate(op->predicate));
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Allocate *op) {
        Type t = upgrade(op->type);
        if (t != op->type) {
            vector<Expr> extents;
            for (Expr e : op->extents) {
                extents.push_back(mutate(e));
            }
            stmt = Allocate::make(op->name, t, extents,
                                  mutate(op->condition), mutate(op->body),
                                  mutate(op->new_expr), op->free_function);
        } else {
            IRMutator::visit(op);
        }
    }
};

// Connect Store nodes to their output buffers
class ConnectOutputBuffers : public IRMutator {
    using IRMutator::visit;

    void visit(const Store *op) {
        Parameter output_buf;
        auto it = env.find(op->name);
        if (it != env.end()) {
            const Function &f = it->second.first;
            int idx = it->second.second;

            // We only want to do this for actual pipeline outputs,
            // even though every Function has an output buffer. Any
            // constraints you set on the output buffer of a Func that
            // isn't actually an output is ignored. This is a language
            // wart.
            if (outputs.count(f.name())) {
                output_buf = f.output_buffers()[idx];
            }
        }

        if (output_buf.defined()) {
            stmt = Store::make(op->name, op->value, op->index, output_buf, const_true());
        } else {
            stmt = op;
        }
    }

    const map<string, pair<Function, int>> &env;
    set<string> outputs;

public:
    ConnectOutputBuffers(const std::map<string, pair<Function, int>> &e,
                         const vector<Function> &o) : env(e) {
        for (auto &f : o) {
            outputs.insert(f.name());
        }
    }
};

}  // namespace

Stmt storage_flattening(Stmt s,
                        const vector<Function> &outputs,
                        const map<string, Function> &env,
                        const Target &target) {
    // Make an environment that makes it easier to figure out which
    // Function corresponds to a tuple component. foo.0, foo.1, foo.2,
    // all point to the function foo.
    map<string, pair<Function, int>> tuple_env;
    for (auto p : env) {
        if (p.second.outputs() > 1) {
            for (int i = 0; i < p.second.outputs(); i++) {
                tuple_env[p.first + "." + std::to_string(i)] = {p.second, i};
            }
        } else {
            tuple_env[p.first] = {p.second, 0};
        }
    }

    s = FlattenDimensions(tuple_env, target).mutate(s);
    s = PromoteToMemoryType().mutate(s);
    s = ConnectOutputBuffers(tuple_env, outputs).mutate(s);
    return s;
}

}
}
<commit_msg>Fix .min/.stride symbols not being connected to Param<commit_after>#include <sstream>

#include "StorageFlattening.h"
#include "IRMutator.h"
#include "IROperator.h"
#include "Scope.h"
#include "Bounds.h"
#include "Parameter.h"

namespace Halide {
namespace Internal {

using std::ostringstream;
using std::string;
using std::vector;
using std::map;
using std::pair;
using std::set;

namespace {

class FlattenDimensions : public IRMutator {
public:
    FlattenDimensions(const map<string, pair<Function, int>> &e,
                      const vector<Function> &o,
                      const Target &t)
        : env(e), target(t) {
        for (auto &f : o) {
            outputs.insert(f.name());
        }
    }
    Scope<int> scope;
private:
    const map<string, pair<Function, int>> &env;
    set<string> outputs;
    const Target ⌖
    Scope<int> realizations;

    Expr flatten_args(const string &name, const vector<Expr> &args,
                      const Buffer<> &buf, const Parameter &param) {
        bool internal = realizations.contains(name);
        Expr idx = target.has_feature(Target::LargeBuffers) ? make_zero(Int(64)) : 0;
        vector<Expr> mins(args.size()), strides(args.size());

        ReductionDomain rdom;
        for (size_t i = 0; i < args.size(); i++) {
            string dim = std::to_string(i);
            string stride_name = name + ".stride." + dim;
            string min_name = name + ".min." + dim;
            string stride_name_constrained = stride_name + ".constrained";
            string min_name_constrained = min_name + ".constrained";
            if (scope.contains(stride_name_constrained)) {
                stride_name = stride_name_constrained;
            }
            if (scope.contains(min_name_constrained)) {
                min_name = min_name_constrained;
            }
            strides[i] = Variable::make(Int(32), stride_name, buf, param, rdom);
            mins[i] = Variable::make(Int(32), min_name, buf, param, rdom);
        }

        if (internal) {
            // f(x, y) -> f[(x-xmin)*xstride + (y-ymin)*ystride] This
            // strategy makes sense when we expect x to cancel with
            // something in xmin.  We use this for internal allocations
            for (size_t i = 0; i < args.size(); i++) {
                if (target.has_feature(Target::LargeBuffers)) {
                    idx += cast<int64_t>(args[i] - mins[i]) * cast<int64_t>(strides[i]);
                } else {
                    idx += (args[i] - mins[i]) * strides[i];
                }
            }
        } else {
            // f(x, y) -> f[x*stride + y*ystride - (xstride*xmin +
            // ystride*ymin)]. The idea here is that the last term
            // will be pulled outside the inner loop. We use this for
            // external buffers, where the mins and strides are likely
            // to be symbolic
            Expr base = target.has_feature(Target::LargeBuffers) ? make_zero(Int(64)) : 0;
            for (size_t i = 0; i < args.size(); i++) {
                if (target.has_feature(Target::LargeBuffers)) {
                    idx += cast<int64_t>(args[i]) * cast<int64_t>(strides[i]);
                    base += cast<int64_t>(mins[i]) * cast<int64_t>(strides[i]);
                } else {
                    idx += args[i] * strides[i];
                    base += mins[i] * strides[i];
                }
            }
            idx -= base;
        }

        return idx;
    }

    using IRMutator::visit;

    void visit(const Realize *op) {
        realizations.push(op->name, 0);

        Stmt body = mutate(op->body);

        // Compute the size
        std::vector<Expr> extents;
        for (size_t i = 0; i < op->bounds.size(); i++) {
            extents.push_back(op->bounds[i].extent);
            extents[i] = mutate(extents[i]);
        }
        Expr condition = mutate(op->condition);

        realizations.pop(op->name);

        vector<int> storage_permutation;
        {
            auto iter = env.find(op->name);
            Function f = iter->second.first;
            internal_assert(iter != env.end()) << "Realize node refers to function not in environment.\n";
            const vector<StorageDim> &storage_dims = f.schedule().storage_dims();
            const vector<string> &args = f.args();
            for (size_t i = 0; i < storage_dims.size(); i++) {
                for (size_t j = 0; j < args.size(); j++) {
                    if (args[j] == storage_dims[i].var) {
                        storage_permutation.push_back((int)j);
                        Expr alignment = storage_dims[i].alignment;
                        if (alignment.defined()) {
                            extents[j] = ((extents[j] + alignment - 1)/alignment)*alignment;
                        }
                    }
                }
                internal_assert(storage_permutation.size() == i+1);
            }
        }

        internal_assert(storage_permutation.size() == op->bounds.size());

        stmt = body;
        internal_assert(op->types.size() == 1);

        // Make the names for the mins, extents, and strides
        int dims = op->bounds.size();
        vector<string> min_name(dims), extent_name(dims), stride_name(dims);
        for (int i = 0; i < dims; i++) {
            string d = std::to_string(i);
            min_name[i] = op->name + ".min." + d;
            stride_name[i] = op->name + ".stride." + d;
            extent_name[i] = op->name + ".extent." + d;
        }
        vector<Expr> min_var(dims), extent_var(dims), stride_var(dims);
        for (int i = 0; i < dims; i++) {
            min_var[i] = Variable::make(Int(32), min_name[i]);
            extent_var[i] = Variable::make(Int(32), extent_name[i]);
            stride_var[i] = Variable::make(Int(32), stride_name[i]);
        }

        // Create a buffer_t object for this allocation.
        if (dims <= 4) {
            BufferBuilder builder;
            Expr first_elem = Load::make(op->types[0], op->name, 0, Buffer<>(), Parameter(),
                                         const_true(op->types[0].lanes()));
            builder.host = Call::make(Handle(), Call::address_of, {first_elem}, Call::PureIntrinsic);
            builder.type = op->types[0];
            builder.dimensions = dims;
            for (int i = 0; i < dims; i++) {
                builder.mins.push_back(min_var[i]);
                builder.extents.push_back(extent_var[i]);
                builder.strides.push_back(stride_var[i]);
            }
            stmt = LetStmt::make(op->name + ".buffer", builder.build(), stmt);
        }

        // Make the allocation node
        stmt = Allocate::make(op->name, op->types[0], extents, condition, stmt);

        // Compute the strides
        for (int i = (int)op->bounds.size()-1; i > 0; i--) {
            int prev_j = storage_permutation[i-1];
            int j = storage_permutation[i];
            Expr stride = stride_var[prev_j] * extent_var[prev_j];
            stmt = LetStmt::make(stride_name[j], stride, stmt);
        }

        // Innermost stride is one
        if (dims > 0) {
            int innermost = storage_permutation.empty() ? 0 : storage_permutation[0];
            stmt = LetStmt::make(stride_name[innermost], 1, stmt);
        }

        // Assign the mins and extents stored
        for (size_t i = op->bounds.size(); i > 0; i--) {
            stmt = LetStmt::make(min_name[i-1], op->bounds[i-1].min, stmt);
            stmt = LetStmt::make(extent_name[i-1], extents[i-1], stmt);
        }
    }

    void visit(const Provide *op) {
        internal_assert(op->values.size() == 1);

        Parameter output_buf;
        auto it = env.find(op->name);
        if (it != env.end()) {
            const Function &f = it->second.first;
            int idx = it->second.second;

            // We only want to do this for actual pipeline outputs,
            // even though every Function has an output buffer. Any
            // constraints you set on the output buffer of a Func that
            // isn't actually an output is ignored. This is a language
            // wart.
            if (outputs.count(f.name())) {
                output_buf = f.output_buffers()[idx];
            }
        }

        Expr idx = mutate(flatten_args(op->name, op->args, Buffer<>(), output_buf));
        Expr value = mutate(op->values[0]);
        stmt = Store::make(op->name, value, idx, output_buf, const_true(value.type().lanes()));
    }

    void visit(const Call *op) {
        if (op->call_type == Call::Halide ||
            op->call_type == Call::Image) {
            internal_assert(op->value_index == 0);
            Expr idx = mutate(flatten_args(op->name, op->args, op->image, op->param));
            expr = Load::make(op->type, op->name, idx, op->image, op->param,
                              const_true(op->type.lanes()));
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const LetStmt *let) {
        // Discover constrained versions of things.
        bool constrained_version_exists = ends_with(let->name, ".constrained");
        if (constrained_version_exists) {
            scope.push(let->name, 0);
        }

        IRMutator::visit(let);

        if (constrained_version_exists) {
            scope.pop(let->name);
        }
    }
};

// Realizations, stores, and loads must all be on types that are
// multiples of 8-bits. This really only affects bools
class PromoteToMemoryType : public IRMutator {
    using IRMutator::visit;

    Type upgrade(Type t) {
        return t.with_bits(((t.bits() + 7)/8)*8);
    }

    void visit(const Call *op) {
        if (op->is_intrinsic(Call::address_of)) {
            Expr load = mutate(op->args[0]);
            if (const Cast *cast = load.as<Cast>()) {
                load = cast->value;
            }
            expr = Call::make(op->type, op->name, {load}, op->call_type);
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Load *op) {
        Type t = upgrade(op->type);
        if (t != op->type) {
            expr = Cast::make(op->type, Load::make(t, op->name, mutate(op->index),
                                                   op->image, op->param, mutate(op->predicate)));
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Store *op) {
        Type t = upgrade(op->value.type());
        if (t != op->value.type()) {
            stmt = Store::make(op->name, Cast::make(t, mutate(op->value)), mutate(op->index),
                                                    op->param, mutate(op->predicate));
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Allocate *op) {
        Type t = upgrade(op->type);
        if (t != op->type) {
            vector<Expr> extents;
            for (Expr e : op->extents) {
                extents.push_back(mutate(e));
            }
            stmt = Allocate::make(op->name, t, extents,
                                  mutate(op->condition), mutate(op->body),
                                  mutate(op->new_expr), op->free_function);
        } else {
            IRMutator::visit(op);
        }
    }
};

}  // namespace

Stmt storage_flattening(Stmt s,
                        const vector<Function> &outputs,
                        const map<string, Function> &env,
                        const Target &target) {
    // Make an environment that makes it easier to figure out which
    // Function corresponds to a tuple component. foo.0, foo.1, foo.2,
    // all point to the function foo.
    map<string, pair<Function, int>> tuple_env;
    for (auto p : env) {
        if (p.second.outputs() > 1) {
            for (int i = 0; i < p.second.outputs(); i++) {
                tuple_env[p.first + "." + std::to_string(i)] = {p.second, i};
            }
        } else {
            tuple_env[p.first] = {p.second, 0};
        }
    }

    s = FlattenDimensions(tuple_env, outputs, target).mutate(s);
    s = PromoteToMemoryType().mutate(s);
    return s;
}

}
}
<|endoftext|>


<commit_before>/*
 * Project: FullereneViewer
 * Version: 1.0
 * Copyright: (C) 2011-14 Dr.Sc.KAWAMOTO,Takuji (Ext)
 * Create: 2011/12/26 18:06:18 JST
 */

#include <assert.h>
#include "SymmetryAxisNormal.h"
#include "CarbonAllotrope.h"
#include "OpenGLUtil.h"

SymmetryAxisNormal::SymmetryAxisNormal(CarbonAllotrope* ca, SymmetryAxis* axis)
  : InteractiveRegularPolygon(ca, 0, 1.0, 2), p_ca(ca), p_axis(axis)
{
}

SymmetryAxisNormal::~SymmetryAxisNormal()
{
}

void SymmetryAxisNormal::reset_interaction()
{
  InteractiveRegularPolygon::reset_interaction();
}

void SymmetryAxisNormal::interaction_original(OriginalForceType force_type,
                                              Interactives* interactives, double delta)
{
  Vector3 north_location;
  Vector3 south_location;
  int north = p_axis->get_north_sequence_no();
  int south = p_axis->get_south_sequence_no();
  switch (p_axis->get_type())
    {
    case AXIS_TYPE_CENTER_OF_RING:
      {
        Ring* north_ring = p_ca->get_ring_by_sequence_no(north);
        Ring* south_ring = p_ca->get_ring_by_sequence_no(south);
        north_location = north_ring->get_center_location();
        south_location = south_ring->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_BOND:
      {
        Bond* north_bond = p_ca->get_bond_by_sequence_no(north);
        Bond* south_bond = p_ca->get_bond_by_sequence_no(south);
        north_location = north_bond->get_center_location();
        south_location = south_bond->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_CARBON:
      {
        Carbon* north_carbon = p_ca->get_carbon_by_sequence_no(north);
        Carbon* south_carbon = p_ca->get_carbon_by_sequence_no(south);
        north_location = north_carbon->get_center_location();
        south_location = south_carbon->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_RING_AND_BOND:
      {
        Ring* north_ring = p_ca->get_ring_by_sequence_no(north);
        Bond* south_bond = p_ca->get_bond_by_sequence_no(south);
        north_location = north_ring->get_center_location();
        south_location = south_bond->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_RING_AND_CARBON:
      {
        Ring* north_ring = p_ca->get_ring_by_sequence_no(north);
        Carbon* south_carbon = p_ca->get_carbon_by_sequence_no(south);
        north_location = north_ring->get_center_location();
        south_location = south_carbon->get_center_location();
      }
      break;
    default:
      assert(0);
    }
  Vector3 center = (north_location + south_location) * 0.5;
  Vector3 normal = north_location - south_location;
  p_normal.clockwise = 1;
  fix_center_location(center);
  fix_radius_length(normal.abs() * 0.6);
  fix_posture(Matrix3(Quaternion(Vector3(0.0, 0.0, 1.0), normal)));
}

void SymmetryAxisNormal::draw_opaque_by_OpenGL(bool selection) const
{
  Vector3 norm = get_normal();
  norm *= p_radius.length;
  OpenGLUtil::set_color(0x808080);
  OpenGLUtil::draw_cylinder(0.1, get_center_location() - norm,
                            get_center_location() + norm);
}

/* Local Variables:	*/
/* mode: c++		*/
/* End:			*/
<commit_msg>対称軸はもうちょっと明るくした。with #53<commit_after>/*
 * Project: FullereneViewer
 * Version: 1.0
 * Copyright: (C) 2011-14 Dr.Sc.KAWAMOTO,Takuji (Ext)
 * Create: 2011/12/26 18:06:18 JST
 */

#include <assert.h>
#include "SymmetryAxisNormal.h"
#include "CarbonAllotrope.h"
#include "OpenGLUtil.h"

SymmetryAxisNormal::SymmetryAxisNormal(CarbonAllotrope* ca, SymmetryAxis* axis)
  : InteractiveRegularPolygon(ca, 0, 1.0, 2), p_ca(ca), p_axis(axis)
{
}

SymmetryAxisNormal::~SymmetryAxisNormal()
{
}

void SymmetryAxisNormal::reset_interaction()
{
  InteractiveRegularPolygon::reset_interaction();
}

void SymmetryAxisNormal::interaction_original(OriginalForceType force_type,
                                              Interactives* interactives, double delta)
{
  Vector3 north_location;
  Vector3 south_location;
  int north = p_axis->get_north_sequence_no();
  int south = p_axis->get_south_sequence_no();
  switch (p_axis->get_type())
    {
    case AXIS_TYPE_CENTER_OF_RING:
      {
        Ring* north_ring = p_ca->get_ring_by_sequence_no(north);
        Ring* south_ring = p_ca->get_ring_by_sequence_no(south);
        north_location = north_ring->get_center_location();
        south_location = south_ring->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_BOND:
      {
        Bond* north_bond = p_ca->get_bond_by_sequence_no(north);
        Bond* south_bond = p_ca->get_bond_by_sequence_no(south);
        north_location = north_bond->get_center_location();
        south_location = south_bond->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_CARBON:
      {
        Carbon* north_carbon = p_ca->get_carbon_by_sequence_no(north);
        Carbon* south_carbon = p_ca->get_carbon_by_sequence_no(south);
        north_location = north_carbon->get_center_location();
        south_location = south_carbon->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_RING_AND_BOND:
      {
        Ring* north_ring = p_ca->get_ring_by_sequence_no(north);
        Bond* south_bond = p_ca->get_bond_by_sequence_no(south);
        north_location = north_ring->get_center_location();
        south_location = south_bond->get_center_location();
      }
      break;
    case AXIS_TYPE_CENTER_OF_RING_AND_CARBON:
      {
        Ring* north_ring = p_ca->get_ring_by_sequence_no(north);
        Carbon* south_carbon = p_ca->get_carbon_by_sequence_no(south);
        north_location = north_ring->get_center_location();
        south_location = south_carbon->get_center_location();
      }
      break;
    default:
      assert(0);
    }
  Vector3 center = (north_location + south_location) * 0.5;
  Vector3 normal = north_location - south_location;
  p_normal.clockwise = 1;
  fix_center_location(center);
  fix_radius_length(normal.abs() * 0.6);
  fix_posture(Matrix3(Quaternion(Vector3(0.0, 0.0, 1.0), normal)));
}

void SymmetryAxisNormal::draw_opaque_by_OpenGL(bool selection) const
{
  Vector3 norm = get_normal();
  norm *= p_radius.length;
  OpenGLUtil::set_color(0xc0c0c0);
  OpenGLUtil::draw_cylinder(0.1, get_center_location() - norm,
                            get_center_location() + norm);
}

/* Local Variables:	*/
/* mode: c++		*/
/* End:			*/
<|endoftext|>


<commit_before><commit_msg>Eliminate the 8-sockets-per-proxy field trial.  Reduce the percentage of clients in the max-sockets tests from 20-25% to 1%.<commit_after><|endoftext|>


<commit_before><commit_msg>#include what you use: <Security/Security.h> for SecKeychainAddCallback and friends following r43492.<commit_after><|endoftext|>


<commit_before><commit_msg>Reset the clear browser data checkbox prefs when the user clicks "Reset to defaults".<commit_after><|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
//  File: InputFld.cpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included
//  in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.
//
//  Description: GMSH converter.
//
////////////////////////////////////////////////////////////////////////////////

#include <string>
#include <iostream>
using namespace std;

#include "InputFld.h"

static std::string npts = LibUtilities::SessionReader::RegisterCmdLineArgument(
                "NumberOfPoints","n","Define number of points to dump output");

namespace Nektar
{
    namespace Utilities
    {
        ModuleKey InputFld::m_className[3] = {
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eInputModule, "fld"), InputFld::create,
                "Reads Fld file."),
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eInputModule, "chk"), InputFld::create,
                "Reads Fld file."),
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eInputModule, "rst"), InputFld::create,
                "Reads Fld file."),
        };

        /**
         * @brief Set up InputFld object.
         *
         */
        InputFld::InputFld(FieldSharedPtr f) : InputModule(f)
        {
            m_allowedFiles.insert("fld");
            m_allowedFiles.insert("chk");
            m_allowedFiles.insert("rst");
        }

        InputFld::~InputFld()
        {
        }

        /**
         *
         */
        void InputFld::Process(po::variables_map &vm)
        {
            if(m_f->m_verbose)
            {
                cout << "Processing input fld file" << endl;
            }

            int i,j;
            string fldending;
            //Determine appropriate field input
            if(m_f->m_inputfiles.count("fld") != 0)
            {
                fldending = "fld";
            }
            else if(m_f->m_inputfiles.count("chk") != 0)
            {
                fldending = "chk";
            }
            else if (m_f->m_inputfiles.count("rst") != 0)
            {
                fldending = "rst";
            }
            else
            {
                ASSERTL0(false,"no input file found");
            }

            if(!m_f->m_fld)
            {
                if(m_f->m_session)
                {
                    m_f->m_fld = MemoryManager<LibUtilities::FieldIO>
                        ::AllocateSharedPtr(m_f->m_session->GetComm());
                }
                else // serial communicator
                {
                    LibUtilities::CommSharedPtr c = LibUtilities::GetCommFactory().CreateInstance("Serial", 0, 0);
                    m_f->m_fld = MemoryManager<LibUtilities::FieldIO>
                        ::AllocateSharedPtr(c);
                }
            }

            if(m_f->m_graph)  // all for restricted expansion defintion when loading field
            {
                // currently load all field (possibly could read data from expansion list
                // but it is re-arranged in expansion)

                const SpatialDomains::ExpansionMap &expansions = m_f->m_graph->GetExpansions();

                // if Range has been speficied it is possible to have a
                // partition which is empty so ccheck this and return if
                // no elements present.
                if(!expansions.size())
                {
                    return;
                }

                m_f->m_exp.resize(1);

                Array<OneD,int> ElementGIDs(expansions.size());
                SpatialDomains::ExpansionMap::const_iterator expIt;

                i = 0;
                for (expIt = expansions.begin(); expIt != expansions.end(); ++expIt)
                {
                    ElementGIDs[i++] = expIt->second->m_geomShPtr->GetGlobalID();
                }

                m_f->m_fielddef.clear();
                m_f->m_data.clear();

                m_f->m_fld->Import(m_f->m_inputfiles[fldending][0],
                                   m_f->m_fielddef,
                                   m_f->m_data,
                                   LibUtilities::NullFieldMetaDataMap,
                                   ElementGIDs);
            }
            else // load all data.
            {
                m_f->m_fld->Import(m_f->m_inputfiles[fldending][0],
                                   m_f->m_fielddef,
                                   m_f->m_data);
            }

            // if m_exp defined presume we want to load all field  into expansions
            if(m_f->m_exp.size())
            {
                int nfields;
                if(vm.count("useSessionVariables"))
                {
                    nfields = m_f->m_session->GetVariables().size();
                }
                else
                {
                    nfields = m_f->m_fielddef[0]->m_fields.size();
                }
                m_f->m_exp.resize(nfields);

                vector<string> vars = m_f->m_session->GetVariables();

                // declare other fields;
                for (i = 1; i < nfields; ++i)
                {
                    if(i < vars.size())
                    {
                        m_f->m_exp[i] = m_f->AppendExpList(m_f->m_fielddef[0]->m_numHomogeneousDir,
                                                           vars[i]);
                    }
                    else
                    {
                        if(vars.size())
                        {
                            m_f->m_exp[i] = m_f->AppendExpList(m_f->m_fielddef[0]->m_numHomogeneousDir,vars[0]);
                        }
                        else
                        {
                            m_f->m_exp[i] = m_f->AppendExpList(m_f->m_fielddef[0]->m_numHomogeneousDir);
                        }
                    }
                }

                for (j = 0; j < nfields; ++j)
                {
                    for (i = 0; i < m_f->m_data.size(); ++i)
                    {
                        m_f->m_exp[j]->ExtractDataToCoeffs(m_f->m_fielddef[i],
                                                           m_f->m_data[i],
                                                           m_f->m_fielddef[i]->m_fields[j],
                                                           m_f->m_exp[j]->UpdateCoeffs());
                    }
                    m_f->m_exp[j]->BwdTrans(m_f->m_exp[j]->GetCoeffs(),
                                            m_f->m_exp[j]->UpdatePhys());
                }

                // if range is defined reset up output field in case or
                // reducing fld definition
                if(vm.count("range"))
                {
                    std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef
                        = m_f->m_exp[0]->GetFieldDefinitions();
                    std::vector<std::vector<NekDouble> > FieldData(FieldDef.size());

                    for (j = 0; j < nfields; ++j)
                    {
                        for (i = 0; i < FieldDef.size(); ++i)
                        {
                            FieldDef[i]->m_fields.push_back(m_f->m_fielddef[0]->m_fields[j]);
                            m_f->m_exp[j]->AppendFieldData(FieldDef[i], FieldData[i]);
                        }
                    }
                    m_f->m_fielddef = FieldDef;
                    m_f->m_data     = FieldData;
                }
            }
        }
    }
}
<commit_msg>Modified to be able to handle strips for Yan's work<commit_after>////////////////////////////////////////////////////////////////////////////////
//
//  File: InputFld.cpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included
//  in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.
//
//  Description: GMSH converter.
//
////////////////////////////////////////////////////////////////////////////////

#include <string>
#include <iostream>
using namespace std;

#include "InputFld.h"

static std::string npts = LibUtilities::SessionReader::RegisterCmdLineArgument(
                "NumberOfPoints","n","Define number of points to dump output");

namespace Nektar
{
    namespace Utilities
    {
        ModuleKey InputFld::m_className[3] = {
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eInputModule, "fld"), InputFld::create,
                "Reads Fld file."),
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eInputModule, "chk"), InputFld::create,
                "Reads Fld file."),
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eInputModule, "rst"), InputFld::create,
                "Reads Fld file."),
        };

        /**
         * @brief Set up InputFld object.
         *
         */
        InputFld::InputFld(FieldSharedPtr f) : InputModule(f)
        {
            m_allowedFiles.insert("fld");
            m_allowedFiles.insert("chk");
            m_allowedFiles.insert("rst");
        }

        InputFld::~InputFld()
        {
        }

        /**
         *
         */
        void InputFld::Process(po::variables_map &vm)
        {
            if(m_f->m_verbose)
            {
                cout << "Processing input fld file" << endl;
            }

            int i,j;
            string fldending;
            //Determine appropriate field input
            if(m_f->m_inputfiles.count("fld") != 0)
            {
                fldending = "fld";
            }
            else if(m_f->m_inputfiles.count("chk") != 0)
            {
                fldending = "chk";
            }
            else if (m_f->m_inputfiles.count("rst") != 0)
            {
                fldending = "rst";
            }
            else
            {
                ASSERTL0(false,"no input file found");
            }

            if(!m_f->m_fld)
            {
                if(m_f->m_session)
                {
                    m_f->m_fld = MemoryManager<LibUtilities::FieldIO>
                        ::AllocateSharedPtr(m_f->m_session->GetComm());
                }
                else // serial communicator
                {
                    LibUtilities::CommSharedPtr c = LibUtilities::GetCommFactory().CreateInstance("Serial", 0, 0);
                    m_f->m_fld = MemoryManager<LibUtilities::FieldIO>
                        ::AllocateSharedPtr(c);
                }
            }

            if(m_f->m_graph)  // all for restricted expansion defintion when loading field
            {
                // currently load all field (possibly could read data from expansion list
                // but it is re-arranged in expansion)

                const SpatialDomains::ExpansionMap &expansions = m_f->m_graph->GetExpansions();

                // if Range has been speficied it is possible to have a
                // partition which is empty so ccheck this and return if
                // no elements present.
                if(!expansions.size())
                {
                    return;
                }

                m_f->m_exp.resize(1);

                Array<OneD,int> ElementGIDs(expansions.size());
                SpatialDomains::ExpansionMap::const_iterator expIt;

                i = 0;
                for (expIt = expansions.begin(); expIt != expansions.end(); ++expIt)
                {
                    ElementGIDs[i++] = expIt->second->m_geomShPtr->GetGlobalID();
                }

                m_f->m_fielddef.clear();
                m_f->m_data.clear();

                m_f->m_fld->Import(m_f->m_inputfiles[fldending][0],
                                   m_f->m_fielddef,
                                   m_f->m_data,
                                   LibUtilities::NullFieldMetaDataMap,
                                   ElementGIDs);
            }
            else // load all data.
            {
                m_f->m_fld->Import(m_f->m_inputfiles[fldending][0],
                                   m_f->m_fielddef,
                                   m_f->m_data);
            }

            // if m_exp defined presume we want to load all field  into expansions
            if(m_f->m_exp.size())
            {
	        int nfields,nstrips;
                if(vm.count("useSessionVariables"))
                {
                    nfields = m_f->m_session->GetVariables().size();
                }
                else
                {
                    nfields = m_f->m_fielddef[0]->m_fields.size();
                }
                m_f->m_exp.resize(nfields);

		m_f->m_session->LoadParameter("Strip_Z",nstrips,1);

                vector<string> vars = m_f->m_session->GetVariables();

                // declare other fields;
                for (i = 1; i < nfields; ++i)
                {
                    if(i < vars.size())
                    {
                        m_f->m_exp[i] = m_f->AppendExpList(m_f->m_fielddef[0]->m_numHomogeneousDir,
                                                           vars[i]);
                    }
                    else
                    {
                        if(vars.size())
                        {
                            m_f->m_exp[i] = m_f->AppendExpList(m_f->m_fielddef[0]->m_numHomogeneousDir,vars[0]);
                        }
                        else
                        {
                            m_f->m_exp[i] = m_f->AppendExpList(m_f->m_fielddef[0]->m_numHomogeneousDir);
                        }
                    }
                }

		for(int s = 0; s < nstrips; ++s) //homogeneous strip varient
		{
		    for (j = 0; j < nfields; ++j)
                    {
		        for (i = 0; i < m_f->m_data.size()/nstrips; ++i)
			{
			    m_f->m_exp[j]->
			      ExtractDataToCoeffs(m_f->m_fielddef[i*nstrips+s],
						  m_f->m_data[i*nstrips+s],
						  m_f->m_fielddef[i*nstrips+s]
						        ->m_fields[j],
						  m_f->m_exp[j]->UpdateCoeffs());
			}
			m_f->m_exp[j]->BwdTrans(m_f->m_exp[j]->GetCoeffs(),
						m_f->m_exp[j]->UpdatePhys());
		    }
		}

                // if range is defined reset up output field in case or
                // reducing fld definition
                if(vm.count("range"))
                {
                    std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef
                        = m_f->m_exp[0]->GetFieldDefinitions();
                    std::vector<std::vector<NekDouble> > FieldData(FieldDef.size());

                    for (j = 0; j < nfields; ++j)
                    {
                        for (i = 0; i < FieldDef.size(); ++i)
                        {
                            FieldDef[i]->m_fields.push_back(m_f->m_fielddef[0]->m_fields[j]);
                            m_f->m_exp[j]->AppendFieldData(FieldDef[i], FieldData[i]);
                        }
                    }
                    m_f->m_fielddef = FieldDef;
                    m_f->m_data     = FieldData;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>When zooming, webkit reports width and height as if the zoom wasn't there (by dividing the pixel size by the zoom factor). If we want actual pixel sizes that the content will best fit, we need to undo that.<commit_after><|endoftext|>


<commit_before>#include "qnitelinearticker.h"

#include <algorithm>
#include <QDebug>

// defines
#define DEFAULT_NUM_STEPS 10
#define DEFAULT_LOOSENESS true

namespace {

  double nice(double x, bool round)
  {
    int exp;
    double f;
    double nicef;

    exp = floor(log10(x));
    f = x / pow(10., exp);

    if (round) {
      if (f<1.5) nicef=1.;
      else if (f<3.) nicef=2.;
      else if (f<7.) nicef=5.;
      else nicef=10.;
    }
    else {
      if (f<=1.) nicef=1.;
      else if (f<=2.) nicef=2.;
      else if (f<=5.) nicef=5.;
      else nicef=10.;
    }

    return nicef*pow(10., exp);
  }

  void fill(QList<qreal>& ticks, qreal min, qreal max, int steps)
  {
    double range = nice(max-min, false);
    double d = nice(range/(steps-1), true);
    double graph_min = floor(min/d) * d;  // loose version of the algo
    double graph_max = ceil(max/d) * d;  // loose version of the algo
    // nFrac is the number of decimal numbers it'd be nice to show
    double nFrac = std::max(-floor(log10(d)), 0.);
    // we use it to better approximate values
    double precision = pow(10, nFrac);

    for (double x=graph_min; x<=graph_max + .5*d; x+=d) {
      // round to the "precision" decimal place
      double val = round(x*precision);
      ticks.append(val/precision);
      //ticks.append(x);
    }
  }

}

QniteLinearTicker::QniteLinearTicker(QObject *parent)
  : QniteTicker(parent),
    m_loose{DEFAULT_LOOSENESS}
{
  setNumSteps(DEFAULT_NUM_STEPS);
}

void QniteLinearTicker::buildTicks()
{
  if (lower() >= upper()) {
    qWarning() << QString("Illegal values for ticker bounds: %1,%2")
                          .arg(lower()).arg(upper());
    return;
  }

  // build major ticks
  QList<qreal> majors;
  fill(majors, lower(), upper(), numSteps());
  setMajorTicks(majors);

  // build min ticks
  QList<qreal> mins;
  for (int i=0; i<majors.size()-1; i++) {
    fill(mins, majors[i], majors[i+1], ceil(numSteps()/2.));
  }

  // remove duplicates
  QSet<qreal> minSet = mins.toSet();
  QSet<qreal> majSet = majors.toSet();

  minSet = minSet.subtract(majSet);

  mins = minSet.toList();
  std::sort(mins.begin(), mins.end(), std::less<qreal>());

  // set tick series
  setMinorTicks(mins);
  setMajorTicks(majors);
}

void QniteLinearTicker::setLooseNiceness(bool is_loose)
{
  m_loose = is_loose;
}

bool QniteLinearTicker::looseNiceness() const
{
  return m_loose;
}

void QniteLinearTicker::reset()
{
  QniteTicker::reset();
  m_loose = DEFAULT_LOOSENESS;
  setNumSteps(DEFAULT_NUM_STEPS);
}

void QniteLinearTicker::setNumSteps(int steps)
{
  if (steps < 2) {
    qWarning() << "Number of steps must be at least 2";
    return;
  }

  QniteTicker::setNumSteps(steps);
}
<commit_msg>simplified duplicates removal<commit_after>#include "qnitelinearticker.h"

#include <algorithm>
#include <QDebug>

// defines
#define DEFAULT_NUM_STEPS 10
#define DEFAULT_LOOSENESS true

namespace {

  double nice(double x, bool round)
  {
    int exp;
    double f;
    double nicef;

    exp = floor(log10(x));
    f = x / pow(10., exp);

    if (round) {
      if (f<1.5) nicef=1.;
      else if (f<3.) nicef=2.;
      else if (f<7.) nicef=5.;
      else nicef=10.;
    }
    else {
      if (f<=1.) nicef=1.;
      else if (f<=2.) nicef=2.;
      else if (f<=5.) nicef=5.;
      else nicef=10.;
    }

    return nicef*pow(10., exp);
  }

  void fill(QList<qreal>& ticks, qreal min, qreal max, int steps)
  {
    double range = nice(max-min, false);
    double d = nice(range/(steps-1), true);
    double graph_min = floor(min/d) * d;  // loose version of the algo
    double graph_max = ceil(max/d) * d;  // loose version of the algo
    // nFrac is the number of decimal numbers it'd be nice to show
    double nFrac = std::max(-floor(log10(d)), 0.);
    // we use it to better approximate values
    double precision = pow(10, nFrac);

    for (double x=graph_min; x<=graph_max + .5*d; x+=d) {
      // round to the "precision" decimal place
      double val = round(x*precision);
      ticks.append(val/precision);
      //ticks.append(x);
    }
  }

}

QniteLinearTicker::QniteLinearTicker(QObject *parent)
  : QniteTicker(parent),
    m_loose{DEFAULT_LOOSENESS}
{
  setNumSteps(DEFAULT_NUM_STEPS);
}

void QniteLinearTicker::buildTicks()
{
  if (lower() >= upper()) {
    qWarning() << QString("Illegal values for ticker bounds: %1,%2")
                          .arg(lower()).arg(upper());
    return;
  }

  // build major ticks
  QList<qreal> majors;
  fill(majors, lower(), upper(), numSteps());
  setMajorTicks(majors);

  // build min ticks
  QList<qreal> mins;
  for (int i=0; i<majors.size()-1; i++) {
    fill(mins, majors[i], majors[i+1], ceil(numSteps()/2.));
  }

  // remove duplicates
  mins = mins.toSet().subtract(majors.toSet()).toList();
  std::sort(mins.begin(), mins.end(), std::less<qreal>());

  // set tick series
  setMinorTicks(mins);
  setMajorTicks(majors);
}

void QniteLinearTicker::setLooseNiceness(bool is_loose)
{
  m_loose = is_loose;
}

bool QniteLinearTicker::looseNiceness() const
{
  return m_loose;
}

void QniteLinearTicker::reset()
{
  QniteTicker::reset();
  m_loose = DEFAULT_LOOSENESS;
  setNumSteps(DEFAULT_NUM_STEPS);
}

void QniteLinearTicker::setNumSteps(int steps)
{
  if (steps < 2) {
    qWarning() << "Number of steps must be at least 2";
    return;
  }

  QniteTicker::setNumSteps(steps);
}
<|endoftext|>