<commit_before>#include "KickEvaluator.hpp"

#include <algorithm>
#include <vector>
#include <math.h>
#include <cmath>

REGISTER_CONFIGURABLE(KickEvaluator)

using namespace std;
using namespace Geometry2d;

ConfigDouble* KickEvaluator::kick_std_dev;
ConfigDouble* KickEvaluator::kick_mean;
ConfigDouble* KickEvaluator::robot_std_dev;
ConfigDouble* KickEvaluator::start_x_offset;

void KickEvaluator::createConfiguration(Configuration* cfg) {
    kick_std_dev     = new ConfigDouble(cfg,
                   "KickEvaluator/kick_std_dev", 0.08);
    kick_mean        = new ConfigDouble(cfg,
                   "KickEvaluator/kick_mean", 0);
    robot_std_dev    = new ConfigDouble(cfg,
                   "KickEvaluator/robot_std_dev", 0.3);
    start_x_offset   = new ConfigDouble(cfg,
                   "KickEvaluator/start_x_offset", 0.1);
}

KickEvaluator::KickEvaluator(SystemState* systemState) : system(systemState) {}

KickResults KickEvaluator::eval_pt_to_pt(Point origin, Point target,
                                         float targetWidth) {
    Point dir = (target - origin).perpCCW().normalized();
    Segment seg = Segment{target + dir * (targetWidth / 2),
                          target - dir * (targetWidth / 2)};

    return eval_pt_to_seg(origin, seg);
}

KickResults KickEvaluator::eval_pt_to_robot(Point origin, Point target) {
    return eval_pt_to_pt(origin, target, 2* Robot_Radius);
}

KickResults KickEvaluator::eval_pt_to_opp_goal(Point origin) {
    Segment their_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()}
    };

    return eval_pt_to_seg(origin, their_goal);
}

KickResults KickEvaluator::eval_pt_to_our_goal(Point origin) {
    Segment our_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0}
    };

    return eval_pt_to_seg(origin, our_goal);
}

KickResults KickEvaluator::eval_pt_to_seg(Point origin, Segment target) {
    Point center = target.center();
    double targetWidth = get_target_angle(origin, target);

    // Polar bot locations
    // <Dist, Angle>
    vector< tuple<double, double> > botLocations =
                            convert_robots_to_polar(origin, center);

    // Convert polar to mean / std_dev / Vertical Scales
    vector<double> botMeans;
    vector<double> botStDevs;
    vector<double> botVertScales;

    for (tuple<double, double>& loc : botLocations){
        botMeans.push_back(get<1>(loc));
        // Want std_dev in radians, not XY distance
        botStDevs.push_back(atan(*robot_std_dev / get<0>(loc)));

        // Robot Past Target
        double distPastTarget = get<0>(loc) - (origin - center).mag();

        // If robot is past target, only use the chance at the target segment
        if (distPastTarget > 0 && fabs(get<1>(loc)) < M_PI / 2) {
            // Evaluate a normal distribution at dist away and scale
            double stdev2 = pow(*robot_std_dev, 2);
            botVertScales.push_back(1 / stdev2 * exp(-0.5 * pow(distPastTarget, 2) / stdev2));
        } else {
            botVertScales.push_back(1);
        }
    }

    // No opponent robots on the field
    if (botMeans.size() == 0) {
        botMeans.push_back(0);
        // Must be non-zero as 1 / botStDev is used
        botStDevs.push_back(1);
        botVertScales.push_back(0);
    }

    // Create KickEvaluator Function parameters
    unique_ptr<KickEvaluatorArgs> keArgs(
                    new KickEvaluatorArgs(*kick_mean, *kick_std_dev,
                                      botMeans, botStDevs, botVertScales,
                                      targetWidth / -2, targetWidth / 2));

    ParallelGradient1DConfig parallelConfig = init_gradient_configs(keArgs.get());

    // Create Gradient Ascent Optimizer and run it
    ParallelGradientAscent1D optimizer(parallelConfig);

    optimizer.execute();

    // Grab the lcoal max values and their X location
    vector<double> maxXValues = optimizer.getMaxXValues();
    vector<double> maxValues = optimizer.getMaxValues();

    // Find the segment out of the list
    double maxX;
    double maxChance;

    // More than one local max
    if (maxXValues.size() > 1) {
        // This happens when there is a "flat" top
        // Find the highest average between the two
        maxX = 0;
        maxChance = 0;

        for (int i = 0; i < maxXValues.size() - 1; i++) {
            double midPoint = (maxXValues.at(i + 1) + maxXValues.at(i)) / 2;
            double chance = get<0>(eval_calculation(midPoint, keArgs.get()));

            if (chance > maxChance) {
                maxX = midPoint;
                maxChance = chance;
            }
        }
    } else {
        maxX = maxXValues.at(0);
        maxChance = maxValues.at(0);
    }

    // Angle in reference to the field
    double realMaxAngle = maxX + (center - origin).angle();
    Line bestKickLine(origin, Point{cos(realMaxAngle), sin(realMaxAngle)});

    // Return point on target segment and chance
    return pair<Point, double>(target.nearestPoint(bestKickLine), maxChance);
}

tuple<double, double> KickEvaluator::eval_calculation(double x, FunctionArgs* fArgs) {
    // 3 Main distribution sets
    // Set #1 : A set of each normal distribution for the obstacles
    // Set #2 : A band pass style distribution that represents a valid target kick
    // Set #3 : A normal distribution representing a kick

    // Set #1 and #2 are combined. To keep the convolution simple, Set #2 is represented using
    //      a Unit step function and just added/subtracted to/from Set #1
    // This will cause problems along the edges when a robot is near since it will go negative
    // But it is not /super/ significant

    // The resulting F(X) represents the convolution of Set #12 and Set #3
    // All of this is calculated with Mathematica

    KickEvaluatorArgs* args = static_cast<KickEvaluatorArgs*>(fArgs);

    // We want the worst chance of success
    double minResults = 1;
    double minIndex = 0;

    // Shortcuts for repeated operations
    double sqrt2pi = sqrt(2*M_PI);
    double sqrtpi_2 = sqrt(M_PI / 2);

    double kmean = args->kickMean;
    double kstdev = args->kickStDev;
    double kstdev2 = pow(kstdev, 2);

    double rmean;
    double rstdev;
    double rstdev2;
    double robotV;

    double kx = kmean - x;

    double fterm; // First term,  Robot normal distribution
    double sterm; // Second term, Left boundary
    double tterm; // Third term,  Right Boundary

    // For each robot distribution in Set #1
    for (int i = 0; i < args->robotMeans.size(); i++) {
        rmean   = args->robotMeans.at(i);
        rstdev  = args->robotStDevs.at(i);
        rstdev2 = pow(rstdev, 2);
        robotV  = args->robotVertScales.at(i);

        fterm = -1 * exp(-0.5 * pow(kx + rmean, 2) / (kstdev2 + rstdev2)) * robotV * sqrt2pi;
        fterm = fterm / sqrt(1 / kstdev2 + 1 / rstdev2);

        sterm = 1 / sqrt(1 / kstdev2) - kstdev * erf((kx + args->boundaryLower) / (sqrt(2) * kstdev));
        sterm *= sqrtpi_2;

        tterm = 1 / sqrt(1 / kstdev2) - kstdev * erf((kx + args->boundaryUpper) / (sqrt(2) * kstdev));
        tterm *= sqrtpi_2;

        double results = 1 / (kstdev * sqrt2pi) * (fterm + sterm - tterm);

        if (results < minResults) {
            minResults = results;
            minIndex = i;
        }
    }

    // Calculate derivative of the convolution
    rmean   = args->robotMeans.at(minIndex);
    rstdev  = args->robotStDevs.at(minIndex);
    rstdev2 = pow(rstdev, 2);
    robotV  = args->robotVertScales.at(minIndex);

    fterm = exp(-0.5 * pow(kx + rmean, 2) / (kstdev2 + rstdev2)) * robotV * sqrt2pi * (kx + rmean);
    fterm = fterm / (sqrt(1 / kstdev2 + 1 / rstdev2) * (kstdev2 + rstdev2));

    sterm = exp(-0.5 * pow(kx + args->boundaryLower, 2) / kstdev2);

    tterm = exp(-0.5 * pow(kx + args->boundaryUpper, 2) / kstdev2);

    double derivative = 1 / (kstdev * sqrt2pi) * (sterm - tterm - fterm);

    return make_tuple(minResults, derivative);
}

double KickEvaluator::get_target_angle(Point origin, Segment target) {
    Point left = target.pt[0] - origin;
    Point right = target.pt[1] - origin;

    return abs(left.angle() - right.angle());
}

vector<Robot*> KickEvaluator::get_valid_robots() {
    vector<Robot*> bots(system->self.size() + system->opp.size());

    auto filter_predicate = [&](const Robot* bot) -> bool {
        return bot != nullptr && bot->visible &&
               find(excluded_robots.begin(), excluded_robots.end(), bot) ==
                    excluded_robots.end();
    };

    auto end_it = copy_if(system->self.begin(), system->self.end(),
                          bots.begin(), filter_predicate);

    end_it = copy_if(system->opp.begin(), system->opp.end(),
                     end_it, filter_predicate);

    bots.resize(distance(bots.begin(), end_it));

    return bots;
}

tuple<double, double> KickEvaluator::rect_to_polar(Point origin,
                                                   Point target,
                                                   Point obstacle) {
    Point obstacleDir = obstacle - origin;
    Point targetDir = target - origin;
    double angle =  obstacleDir.angle() - targetDir.angle();

    // Force between -pi and pi
    angle = atan2(sin(angle), cos(angle));

    return make_tuple(obstacleDir.mag(), angle);
}

vector< tuple<double, double> > KickEvaluator::convert_robots_to_polar(Point origin, Point target) {
    vector<Robot*> bots = get_valid_robots();
    vector< tuple<double, double> > botLocations;

    // Convert each bot position to polar
    for_each(bots.begin(), bots.end(),
             [&botLocations, target, origin, this](Robot* bot) {
                botLocations.push_back(rect_to_polar(origin,
                                                      target,
                                                      bot->pos));
             });

    // Convert imaginary obstacles to polar
    for_each(hypothetical_robot_locations.begin(),
             hypothetical_robot_locations.end(),
             [&botLocations, target, origin, this](Point obstacle) {
                botLocations.push_back(rect_to_polar(origin,
                                                      target,
                                                      obstacle));
             });

    return botLocations;
}

ParallelGradient1DConfig KickEvaluator::init_gradient_configs(KickEvaluatorArgs* keArgs) {
    // Create list of single configs
    vector<Gradient1DConfig> singleGradientConfigs;

    // Standard Gradient Configs
    double dxError = 0.01;
    double maxXMovement = *min_element(keArgs->robotStDevs.begin(), keArgs->robotStDevs.end()) / 5;
    double temperatureDescent = 0.5;
    double temperatureMin = 0.01;
    int maxIterations = 100;
    double maxValue = 1;
    double maxThresh = 0.01;
    double boundaryLower = keArgs->boundaryLower;
    double boundaryUpper = keArgs->boundaryUpper;

    // PrevStart, Start
    vector< tuple<double, double> > xStarts;

    double startX = boundaryLower + *start_x_offset * keArgs->kickStDev;
    xStarts.push_back(make_tuple(boundaryLower, startX));

    startX = boundaryUpper - *start_x_offset * keArgs->kickStDev;
    xStarts.push_back(make_tuple(boundaryUpper, startX));

    // For each robot
    for (int i = 0; i < keArgs->robotMeans.size(); i++) {
        // -1 or 1
        for (int side = -1; side <= 1; side += 2) {
            startX = keArgs->robotMeans.at(i) + side * *start_x_offset * keArgs->robotStDevs.at(i);

            xStarts.push_back(make_tuple(keArgs->robotMeans.at(i), startX));
        }
    }

    // Force into ascending order to make things simpler
    sort(xStarts.begin(), xStarts.end(), [&](tuple<double, double> a, tuple<double, double> b) {
        return get<1>(a) < get<1>(b);
    });

    // Create list of configs
    for (tuple<double, double> xStart : xStarts) {
        singleGradientConfigs.push_back(
            Gradient1DConfig(&eval_calculation, keArgs,
                             get<1>(xStart), get<0>(xStart),
                             dxError, maxXMovement,
                             temperatureDescent, temperatureMin,
                             maxIterations, maxValue, maxThresh));

    }

    // Create config from all the singles and the min std_dev
    double xCombineThresh = *min_element(keArgs->robotStDevs.begin(), keArgs->robotStDevs.end()) * *start_x_offset / 2;

    return ParallelGradient1DConfig(singleGradientConfigs, xCombineThresh);
}<commit_msg>Fixed case where there is only one local max Switched some stuff to the utils functions<commit_after>#include "KickEvaluator.hpp"
#include <Utils.hpp>
#include <Geometry2d/Util.hpp>

#include <algorithm>
#include <vector>
#include <math.h>
#include <cmath>

REGISTER_CONFIGURABLE(KickEvaluator)

using namespace std;
using namespace Geometry2d;

ConfigDouble* KickEvaluator::kick_std_dev;
ConfigDouble* KickEvaluator::kick_mean;
ConfigDouble* KickEvaluator::robot_std_dev;
ConfigDouble* KickEvaluator::start_x_offset;

void KickEvaluator::createConfiguration(Configuration* cfg) {
    kick_std_dev     = new ConfigDouble(cfg,
                   "KickEvaluator/kick_std_dev", 0.08);
    kick_mean        = new ConfigDouble(cfg,
                   "KickEvaluator/kick_mean", 0);
    robot_std_dev    = new ConfigDouble(cfg,
                   "KickEvaluator/robot_std_dev", 0.3);
    start_x_offset   = new ConfigDouble(cfg,
                   "KickEvaluator/start_x_offset", 0.1);
}

KickEvaluator::KickEvaluator(SystemState* systemState) : system(systemState) {}

KickResults KickEvaluator::eval_pt_to_pt(Point origin, Point target,
                                         float targetWidth) {
    Point dir = (target - origin).perpCCW().normalized();
    Segment seg = Segment{target + dir * (targetWidth / 2),
                          target - dir * (targetWidth / 2)};

    return eval_pt_to_seg(origin, seg);
}

KickResults KickEvaluator::eval_pt_to_robot(Point origin, Point target) {
    return eval_pt_to_pt(origin, target, 2* Robot_Radius);
}

KickResults KickEvaluator::eval_pt_to_opp_goal(Point origin) {
    Segment their_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()}
    };

    return eval_pt_to_seg(origin, their_goal);
}

KickResults KickEvaluator::eval_pt_to_our_goal(Point origin) {
    Segment our_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0}
    };

    return eval_pt_to_seg(origin, our_goal);
}

KickResults KickEvaluator::eval_pt_to_seg(Point origin, Segment target) {
    Point center = target.center();
    double targetWidth = get_target_angle(origin, target);

    // Polar bot locations
    // <Dist, Angle>
    vector< tuple<double, double> > botLocations =
                            convert_robots_to_polar(origin, center);

    // Convert polar to mean / std_dev / Vertical Scales
    vector<double> botMeans;
    vector<double> botStDevs;
    vector<double> botVertScales;

    for (tuple<double, double>& loc : botLocations){
        botMeans.push_back(get<1>(loc));
        // Want std_dev in radians, not XY distance
        botStDevs.push_back(atan(*robot_std_dev / get<0>(loc)));

        // Robot Past Target
        double distPastTarget = get<0>(loc) - (origin - center).mag();

        // If robot is past target, only use the chance at the target segment
        if (distPastTarget > 0 && fabs(get<1>(loc)) < M_PI / 2) {
            // Evaluate a normal distribution at dist away and scale
            double stdev2 = pow(*robot_std_dev, 2);
            botVertScales.push_back(1 / stdev2 * exp(-0.5 * pow(distPastTarget, 2) / stdev2));
        } else {
            botVertScales.push_back(1);
        }
    }

    // No opponent robots on the field
    if (botMeans.size() == 0) {
        botMeans.push_back(0);
        // Must be non-zero as 1 / botStDev is used
        botStDevs.push_back(1);
        botVertScales.push_back(0);
    }

    // Create KickEvaluator Function parameters
    unique_ptr<KickEvaluatorArgs> keArgs(
                    new KickEvaluatorArgs(*kick_mean, *kick_std_dev,
                                      botMeans, botStDevs, botVertScales,
                                      targetWidth / -2, targetWidth / 2));

    ParallelGradient1DConfig parallelConfig = init_gradient_configs(keArgs.get());

    // Create Gradient Ascent Optimizer and run it
    ParallelGradientAscent1D optimizer(parallelConfig);

    optimizer.execute();

    // Grab the lcoal max values and their X location
    vector<double> maxXValues = optimizer.getMaxXValues();
    vector<double> maxValues = optimizer.getMaxValues();

    // Default to a local max
    int index = distance(maxValues.begin(), max_element(maxValues.begin(), maxValues.end()));
    double maxX = maxXValues.at(index);
    double maxChance = maxValues.at(index);

    // See if there is a segment which is longer
    // Since local maxes stop on either side of the segment
    if (maxXValues.size() > 1) {
        for (int i = 0; i < maxXValues.size() - 1; i++) {
            // Finds the score at the average between two local maxes
            double midPoint = (maxXValues.at(i) + maxXValues.at(i + 1)) / 2;
            double chance = get<0>(eval_calculation(midPoint, keArgs.get()));

            if (chance > maxChance || nearlyEqual(chance, maxChance)) {
                maxX = midPoint;
                maxChance = chance;
            }
        }
    }

    // Angle in reference to the field
    double realMaxAngle = maxX + (center - origin).angle();
    Line bestKickLine(origin, Point{cos(realMaxAngle), sin(realMaxAngle)});

    // Return point on target segment and chance
    return pair<Point, double>(target.nearestPoint(bestKickLine), maxChance);
}

tuple<double, double> KickEvaluator::eval_calculation(double x, FunctionArgs* fArgs) {
    // 3 Main distribution sets
    // Set #1 : A set of each normal distribution for the obstacles
    // Set #2 : A band pass style distribution that represents a valid target kick
    // Set #3 : A normal distribution representing a kick

    // Set #1 and #2 are combined. To keep the convolution simple, Set #2 is represented using
    //      a Unit step function and just added/subtracted to/from Set #1
    // This will cause problems along the edges when a robot is near since it will go negative
    // But it is not /super/ significant

    // The resulting F(X) represents the convolution of Set #12 and Set #3
    // All of this is calculated with Mathematica

    KickEvaluatorArgs* args = static_cast<KickEvaluatorArgs*>(fArgs);

    // We want the worst chance of success
    double minResults = 1;
    double minIndex = 0;

    // Shortcuts for repeated operations
    double sqrt2pi = sqrt(2*M_PI);
    double sqrtpi_2 = sqrt(M_PI / 2);

    double kmean = args->kickMean;
    double kstdev = args->kickStDev;
    double kstdev2 = pow(kstdev, 2);

    double rmean;
    double rstdev;
    double rstdev2;
    double robotV;

    double kx = kmean - x;

    double fterm; // First term,  Robot normal distribution
    double sterm; // Second term, Left boundary
    double tterm; // Third term,  Right Boundary

    // For each robot distribution in Set #1
    for (int i = 0; i < args->robotMeans.size(); i++) {
        rmean   = args->robotMeans.at(i);
        rstdev  = args->robotStDevs.at(i);
        rstdev2 = pow(rstdev, 2);
        robotV  = args->robotVertScales.at(i);

        fterm = -1 * exp(-0.5 * pow(kx + rmean, 2) / (kstdev2 + rstdev2)) * robotV * sqrt2pi;
        fterm = fterm / sqrt(1 / kstdev2 + 1 / rstdev2);

        sterm = 1 / sqrt(1 / kstdev2) - kstdev * erf((kx + args->boundaryLower) / (sqrt(2) * kstdev));
        sterm *= sqrtpi_2;

        tterm = 1 / sqrt(1 / kstdev2) - kstdev * erf((kx + args->boundaryUpper) / (sqrt(2) * kstdev));
        tterm *= sqrtpi_2;

        double results = 1 / (kstdev * sqrt2pi) * (fterm + sterm - tterm);

        if (results < minResults) {
            minResults = results;
            minIndex = i;
        }
    }

    // Calculate derivative of the convolution
    rmean   = args->robotMeans.at(minIndex);
    rstdev  = args->robotStDevs.at(minIndex);
    rstdev2 = pow(rstdev, 2);
    robotV  = args->robotVertScales.at(minIndex);

    fterm = exp(-0.5 * pow(kx + rmean, 2) / (kstdev2 + rstdev2)) * robotV * sqrt2pi * (kx + rmean);
    fterm = fterm / (sqrt(1 / kstdev2 + 1 / rstdev2) * (kstdev2 + rstdev2));

    sterm = exp(-0.5 * pow(kx + args->boundaryLower, 2) / kstdev2);

    tterm = exp(-0.5 * pow(kx + args->boundaryUpper, 2) / kstdev2);

    double derivative = 1 / (kstdev * sqrt2pi) * (sterm - tterm - fterm);

    return make_tuple(minResults, derivative);
}

double KickEvaluator::get_target_angle(Point origin, Segment target) {
    Point left = target.pt[0] - origin;
    Point right = target.pt[1] - origin;

    return abs(left.angle() - right.angle());
}

vector<Robot*> KickEvaluator::get_valid_robots() {
    vector<Robot*> bots(system->self.size() + system->opp.size());

    auto filter_predicate = [&](const Robot* bot) -> bool {
        return bot != nullptr && bot->visible &&
               find(excluded_robots.begin(), excluded_robots.end(), bot) ==
                    excluded_robots.end();
    };

    auto end_it = copy_if(system->self.begin(), system->self.end(),
                          bots.begin(), filter_predicate);

    end_it = copy_if(system->opp.begin(), system->opp.end(),
                     end_it, filter_predicate);

    bots.resize(distance(bots.begin(), end_it));

    return bots;
}

tuple<double, double> KickEvaluator::rect_to_polar(Point origin,
                                                   Point target,
                                                   Point obstacle) {
    Point obstacleDir = obstacle - origin;
    Point targetDir = target - origin;
    double angle =  obstacleDir.angle() - targetDir.angle();

    return make_tuple(obstacleDir.mag(), fixAngleRadians(angle));
}

vector< tuple<double, double> > KickEvaluator::convert_robots_to_polar(Point origin, Point target) {
    vector<Robot*> bots = get_valid_robots();
    vector< tuple<double, double> > botLocations;

    // Convert each bot position to polar
    for_each(bots.begin(), bots.end(),
             [&botLocations, target, origin, this](Robot* bot) {
                botLocations.push_back(rect_to_polar(origin,
                                                      target,
                                                      bot->pos));
             });

    // Convert imaginary obstacles to polar
    for_each(hypothetical_robot_locations.begin(),
             hypothetical_robot_locations.end(),
             [&botLocations, target, origin, this](Point obstacle) {
                botLocations.push_back(rect_to_polar(origin,
                                                      target,
                                                      obstacle));
             });

    return botLocations;
}

ParallelGradient1DConfig KickEvaluator::init_gradient_configs(KickEvaluatorArgs* keArgs) {
    // Create list of single configs
    vector<Gradient1DConfig> singleGradientConfigs;

    // Standard Gradient Configs
    double dxError = 0.01;
    double maxXMovement = *min_element(keArgs->robotStDevs.begin(), keArgs->robotStDevs.end()) / 5;
    double temperatureDescent = 0.5;
    double temperatureMin = 0.01;
    int maxIterations = 100;
    double maxValue = 1;
    double maxThresh = 0.01;
    double boundaryLower = keArgs->boundaryLower;
    double boundaryUpper = keArgs->boundaryUpper;

    // PrevStart, Start
    vector< tuple<double, double> > xStarts;

    double startX = boundaryLower + *start_x_offset * keArgs->kickStDev;
    xStarts.push_back(make_tuple(boundaryLower, startX));

    startX = boundaryUpper - *start_x_offset * keArgs->kickStDev;
    xStarts.push_back(make_tuple(boundaryUpper, startX));

    // For each robot
    for (int i = 0; i < keArgs->robotMeans.size(); i++) {
        // -1 or 1
        for (int side = -1; side <= 1; side += 2) {
            startX = keArgs->robotMeans.at(i) + side * *start_x_offset * keArgs->robotStDevs.at(i);

            xStarts.push_back(make_tuple(keArgs->robotMeans.at(i), startX));
        }
    }

    // Force into ascending order to make things simpler
    sort(xStarts.begin(), xStarts.end(), [&](tuple<double, double> a, tuple<double, double> b) {
        return get<1>(a) < get<1>(b);
    });

    // Create list of configs
    for (tuple<double, double> xStart : xStarts) {
        singleGradientConfigs.push_back(
            Gradient1DConfig(&eval_calculation, keArgs,
                             get<1>(xStart), get<0>(xStart),
                             dxError, maxXMovement,
                             temperatureDescent, temperatureMin,
                             maxIterations, maxValue, maxThresh));

    }

    // Create config from all the singles and the min std_dev
    double xCombineThresh = *min_element(keArgs->robotStDevs.begin(), keArgs->robotStDevs.end()) * *start_x_offset / 2;

    return ParallelGradient1DConfig(singleGradientConfigs, xCombineThresh);
}<|endoftext|>


<commit_before><commit_msg>ZedPlugin color issue solved<commit_after><|endoftext|>


<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: jglaser

#include "MolecularForceCompute.h"

#include "hoomd/CachedAllocator.h"
#include "hoomd/Autotuner.h"

#ifdef ENABLE_CUDA
#include "MolecularForceCompute.cuh"
#endif

#include <string.h>
#include <map>

namespace py = pybind11;

/*! \file MolecularForceCompute.cc
    \brief Contains code for the MolecularForceCompute class
*/

/*! \param sysdef SystemDefinition containing the ParticleData to compute forces on
*/
MolecularForceCompute::MolecularForceCompute(std::shared_ptr<SystemDefinition> sysdef)
    : ForceConstraint(sysdef), m_molecule_tag(m_exec_conf), m_n_molecules_global(0), m_dirty(true),
      m_molecule_list(m_exec_conf), m_molecule_length(m_exec_conf), m_molecule_order(m_exec_conf),
      m_molecule_idx(m_exec_conf)
    {
    // connect to the ParticleData to recieve notifications when particles change order in memory
    m_pdata->getParticleSortSignal().connect<MolecularForceCompute, &MolecularForceCompute::setDirty>(this);

    TAG_ALLOCATION(m_molecule_tag);
    TAG_ALLOCATION(m_molecule_list);
    TAG_ALLOCATION(m_molecule_length);
    TAG_ALLOCATION(m_molecule_order);
    TAG_ALLOCATION(m_molecule_idx);

    #ifdef ENABLE_CUDA
    if (m_exec_conf->isCUDAEnabled())
        {
        // initialize autotuner
        std::vector<unsigned int> valid_params;
        for (unsigned int block_size = 32; block_size <= 1024; block_size += 32)
            valid_params.push_back(block_size);

        m_tuner_fill.reset(new Autotuner(valid_params, 5, 100000, "fill_molecule_table", this->m_exec_conf));
        }
    #endif
    }

//! Destructor
MolecularForceCompute::~MolecularForceCompute()
    {
    m_pdata->getParticleSortSignal().disconnect<MolecularForceCompute, &MolecularForceCompute::setDirty>(this);
    }

#ifdef ENABLE_CUDA
void MolecularForceCompute::initMoleculesGPU()
    {
    if (m_prof) m_prof->push(m_exec_conf,"init molecules");

    unsigned int nptl_local = m_pdata->getN() + m_pdata->getNGhosts();

    unsigned int n_local_molecules = 0;

    // maximum molecule length
    unsigned int nmax = 0;

    // number of local particles that are part of molecules
    unsigned int n_local_ptls_in_molecules = 0;

    // resize to maximum possible number of local molecules
    m_molecule_length.resize(nptl_local);
    m_molecule_idx.resize(nptl_local);

    ScopedAllocation<unsigned int> d_idx_sorted_by_tag(m_exec_conf->getCachedAllocator(), nptl_local);
    ScopedAllocation<unsigned int> d_local_molecule_tags(m_exec_conf->getCachedAllocator(), nptl_local);

        {
        ArrayHandle<unsigned int> d_molecule_tag(m_molecule_tag, access_location::device, access_mode::read);
        ArrayHandle<unsigned int> d_tag(m_pdata->getTags(), access_location::device, access_mode::read);
        ArrayHandle<unsigned int> d_molecule_length(m_molecule_length, access_location::device, access_mode::overwrite);
        ArrayHandle<unsigned int> d_molecule_idx(m_molecule_idx, access_location::device, access_mode::overwrite);

        // temporary buffers
        ScopedAllocation<unsigned int> d_local_unique_molecule_tags(m_exec_conf->getCachedAllocator(), m_n_molecules_global);
        ScopedAllocation<unsigned int> d_sorted_by_tag(m_exec_conf->getCachedAllocator(), nptl_local);

        gpu_sort_by_molecule(nptl_local,
            d_tag.data,
            d_molecule_tag.data,
            d_local_molecule_tags.data,
            d_local_unique_molecule_tags.data,
            d_molecule_idx.data,
            d_sorted_by_tag.data,
            d_idx_sorted_by_tag.data,
            d_molecule_length.data,
            n_local_molecules,
            nmax,
            n_local_ptls_in_molecules,
            m_exec_conf->getCachedAllocator());

        if (m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();
        }

    // set up indexer
    m_molecule_indexer = Index2D(nmax, n_local_molecules);

    m_exec_conf->msg->notice(7) << "MolecularForceCompute: " << n_local_molecules << " molecules, "
        << n_local_ptls_in_molecules << " particles in molecules " << std::endl;

    // resize molecule list
    m_molecule_list.resize(m_molecule_indexer.getNumElements());

    // resize molecule lookup to size of local particle data
    m_molecule_order.resize(m_pdata->getMaxN());

        {
        // write out molecule list and order
        ArrayHandle<unsigned int> d_molecule_list(m_molecule_list, access_location::device, access_mode::overwrite);
        ArrayHandle<unsigned int> d_molecule_order(m_molecule_order, access_location::device, access_mode::overwrite);
        ArrayHandle<unsigned int> d_molecule_idx(m_molecule_idx, access_location::device, access_mode::read);

        m_tuner_fill->begin();
        unsigned int block_size = m_tuner_fill->getParam();

        gpu_fill_molecule_table(nptl_local,
            n_local_ptls_in_molecules,
            m_molecule_indexer,
            d_molecule_idx.data,
            d_local_molecule_tags.data,
            d_idx_sorted_by_tag.data,
            d_molecule_list.data,
            d_molecule_order.data,
            block_size,
            m_exec_conf->getCachedAllocator());

        if (m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();

        m_tuner_fill->end();
        }

    #ifdef ENABLE_CUDA
    if (m_exec_conf->isCUDAEnabled())
        {
        auto gpu_map = m_exec_conf->getGPUIds();

        if (m_exec_conf->getNumActiveGPUs() > 1)
            {
            for (unsigned int idev = 0; idev < m_exec_conf->getNumActiveGPUs(); ++idev)
                {
                auto range = m_pdata->getGPUPartition().getRange(idev);
                unsigned int nelem =  range.second - range.first;

                // skip if no hint set
                if (!nelem)
                    continue;

                cudaMemAdvise(m_molecule_idx.get()+range.first, sizeof(unsigned int)*nelem, cudaMemAdviseSetPreferredLocation, gpu_map[idev]);
                cudaMemPrefetchAsync(m_molecule_idx.get()+range.first, sizeof(unsigned int)*nelem, gpu_map[idev]);
                }

            CHECK_CUDA_ERROR();
            }
        }
    #endif

    if (m_prof) m_prof->pop(m_exec_conf);
    }
#endif

void MolecularForceCompute::initMolecules()
    {
    // return early if no molecules are defined
    if (!m_n_molecules_global) return;

    m_exec_conf->msg->notice(7) << "MolecularForceCompute initializing molecule table" << std::endl;

    #ifdef ENABLE_CUDA
    if (m_exec_conf->isCUDAEnabled())
        {
        initMoleculesGPU();
        return;
        }
    #endif

    if (m_prof) m_prof->push("init molecules");

    // construct local molecule table
    unsigned int nptl_local = m_pdata->getN() + m_pdata->getNGhosts();

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

    std::set<unsigned int> local_molecule_tags;

    unsigned int n_local_molecules = 0;

    std::vector<unsigned int> local_molecule_idx(nptl_local, NO_MOLECULE);

    // resize molecule lookup to size of local particle data
    m_molecule_order.resize(m_pdata->getMaxN());

    // sort local molecules by molecule tag, and inside the molecule by ptl tag
    std::map<unsigned int, std::set<unsigned int> > local_molecules_sorted;

    for (unsigned int iptl = 0; iptl < nptl_local; ++iptl)
        {
        unsigned int tag = h_tag.data[iptl];
        assert(tag < m_molecule_tag.getNumElements());

        unsigned int mol_tag = h_molecule_tag.data[tag];
        if (mol_tag == NO_MOLECULE) continue;

        auto it = local_molecules_sorted.find(mol_tag);
        if (it == local_molecules_sorted.end())
            {
            auto res = local_molecules_sorted.insert(std::make_pair(mol_tag,std::set<unsigned int>()));
            assert(res.second);
            it = res.first;
            }

        it->second.insert(tag);
        }

    n_local_molecules = local_molecules_sorted.size();

    m_exec_conf->msg->notice(7) << "MolecularForceCompute: " << n_local_molecules << " molecules" << std::endl;

    m_molecule_length.resize(n_local_molecules);

    ArrayHandle<unsigned int> h_molecule_length(m_molecule_length, access_location::host, access_mode::overwrite);

    // reset lengths
    for (unsigned int imol = 0; imol < n_local_molecules; ++imol)
        {
        h_molecule_length.data[imol] = 0;
        }

    // count molecule lengths
    unsigned int i = 0;
    for (auto it = local_molecules_sorted.begin(); it != local_molecules_sorted.end(); ++it)
        {
        h_molecule_length.data[i++] = it->second.size();
        }

    // find maximum length
    unsigned nmax = 0;
    for (unsigned int imol = 0; imol < n_local_molecules; ++imol)
        {
        if (h_molecule_length.data[imol] > nmax)
            {
            nmax = h_molecule_length.data[imol];
            }
        }

    // set up indexer
    m_molecule_indexer = Index2D(nmax, n_local_molecules);

    // resize molecule list
    m_molecule_list.resize(m_molecule_indexer.getNumElements());

    // reset lengths again
    for (unsigned int imol = 0; imol < n_local_molecules; ++imol)
        {
        h_molecule_length.data[imol] = 0;
        }

    // reset molecule order
    ArrayHandle<unsigned int> h_molecule_order(m_molecule_order, access_location::host, access_mode::overwrite);
    memset(h_molecule_order.data, 0, sizeof(unsigned int)*(m_pdata->getN() + m_pdata->getNGhosts()));

    // resize reverse-lookup
    m_molecule_idx.resize(nptl_local);

    // fill molecule list
    ArrayHandle<unsigned int> h_molecule_list(m_molecule_list, access_location::host, access_mode::overwrite);
    ArrayHandle<unsigned int> h_molecule_idx(m_molecule_idx, access_location::host, access_mode::overwrite);
    ArrayHandle<unsigned int> h_rtag(m_pdata->getRTags(), access_location::host, access_mode::read);

    // reset reverse lookup
    memset(h_molecule_idx.data, 0, sizeof(unsigned int)*nptl_local);

    unsigned int i_mol = 0;
    for (auto it_mol = local_molecules_sorted.begin(); it_mol != local_molecules_sorted.end(); ++it_mol)
        {
        for (std::set<unsigned int>::iterator it_tag = it_mol->second.begin(); it_tag != it_mol->second.end(); ++it_tag)
            {
            unsigned int n = h_molecule_length.data[i_mol]++;
            unsigned int ptl_idx = h_rtag.data[*it_tag];
            assert(ptl_idx < m_pdata->getN() + m_pdata->getNGhosts());
            h_molecule_list.data[m_molecule_indexer(n, i_mol)] = ptl_idx;
            h_molecule_idx.data[ptl_idx] = i_mol;
            h_molecule_order.data[ptl_idx] = n;
            }
        i_mol ++;
        }

    if (m_prof) m_prof->pop(m_exec_conf);
    }

void export_MolecularForceCompute(py::module& m)
    {
    py::class_< MolecularForceCompute, std::shared_ptr<MolecularForceCompute> >(m, "MolecularForceCompute", py::base<ForceConstraint>())
    .def(py::init< std::shared_ptr<SystemDefinition> >())
    ;
    }
<commit_msg>setAccessedBy memory hint on molecule tables<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: jglaser

#include "MolecularForceCompute.h"

#include "hoomd/CachedAllocator.h"
#include "hoomd/Autotuner.h"

#ifdef ENABLE_CUDA
#include "MolecularForceCompute.cuh"
#endif

#include <string.h>
#include <map>

namespace py = pybind11;

/*! \file MolecularForceCompute.cc
    \brief Contains code for the MolecularForceCompute class
*/

/*! \param sysdef SystemDefinition containing the ParticleData to compute forces on
*/
MolecularForceCompute::MolecularForceCompute(std::shared_ptr<SystemDefinition> sysdef)
    : ForceConstraint(sysdef), m_molecule_tag(m_exec_conf), m_n_molecules_global(0), m_dirty(true),
      m_molecule_list(m_exec_conf), m_molecule_length(m_exec_conf), m_molecule_order(m_exec_conf),
      m_molecule_idx(m_exec_conf)
    {
    // connect to the ParticleData to recieve notifications when particles change order in memory
    m_pdata->getParticleSortSignal().connect<MolecularForceCompute, &MolecularForceCompute::setDirty>(this);

    TAG_ALLOCATION(m_molecule_tag);
    TAG_ALLOCATION(m_molecule_list);
    TAG_ALLOCATION(m_molecule_length);
    TAG_ALLOCATION(m_molecule_order);
    TAG_ALLOCATION(m_molecule_idx);

    #ifdef ENABLE_CUDA
    if (m_exec_conf->isCUDAEnabled())
        {
        // initialize autotuner
        std::vector<unsigned int> valid_params;
        for (unsigned int block_size = 32; block_size <= 1024; block_size += 32)
            valid_params.push_back(block_size);

        m_tuner_fill.reset(new Autotuner(valid_params, 5, 100000, "fill_molecule_table", this->m_exec_conf));
        }
    #endif
    }

//! Destructor
MolecularForceCompute::~MolecularForceCompute()
    {
    m_pdata->getParticleSortSignal().disconnect<MolecularForceCompute, &MolecularForceCompute::setDirty>(this);
    }

#ifdef ENABLE_CUDA
void MolecularForceCompute::initMoleculesGPU()
    {
    if (m_prof) m_prof->push(m_exec_conf,"init molecules");

    unsigned int nptl_local = m_pdata->getN() + m_pdata->getNGhosts();

    unsigned int n_local_molecules = 0;

    // maximum molecule length
    unsigned int nmax = 0;

    // number of local particles that are part of molecules
    unsigned int n_local_ptls_in_molecules = 0;

    // resize to maximum possible number of local molecules
    m_molecule_length.resize(nptl_local);
    m_molecule_idx.resize(nptl_local);

    ScopedAllocation<unsigned int> d_idx_sorted_by_tag(m_exec_conf->getCachedAllocator(), nptl_local);
    ScopedAllocation<unsigned int> d_local_molecule_tags(m_exec_conf->getCachedAllocator(), nptl_local);

        {
        ArrayHandle<unsigned int> d_molecule_tag(m_molecule_tag, access_location::device, access_mode::read);
        ArrayHandle<unsigned int> d_tag(m_pdata->getTags(), access_location::device, access_mode::read);
        ArrayHandle<unsigned int> d_molecule_length(m_molecule_length, access_location::device, access_mode::overwrite);
        ArrayHandle<unsigned int> d_molecule_idx(m_molecule_idx, access_location::device, access_mode::overwrite);

        // temporary buffers
        ScopedAllocation<unsigned int> d_local_unique_molecule_tags(m_exec_conf->getCachedAllocator(), m_n_molecules_global);
        ScopedAllocation<unsigned int> d_sorted_by_tag(m_exec_conf->getCachedAllocator(), nptl_local);

        gpu_sort_by_molecule(nptl_local,
            d_tag.data,
            d_molecule_tag.data,
            d_local_molecule_tags.data,
            d_local_unique_molecule_tags.data,
            d_molecule_idx.data,
            d_sorted_by_tag.data,
            d_idx_sorted_by_tag.data,
            d_molecule_length.data,
            n_local_molecules,
            nmax,
            n_local_ptls_in_molecules,
            m_exec_conf->getCachedAllocator());

        if (m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();
        }

    // set up indexer
    m_molecule_indexer = Index2D(nmax, n_local_molecules);

    m_exec_conf->msg->notice(7) << "MolecularForceCompute: " << n_local_molecules << " molecules, "
        << n_local_ptls_in_molecules << " particles in molecules " << std::endl;

    // resize molecule list
    m_molecule_list.resize(m_molecule_indexer.getNumElements());

    // resize molecule lookup to size of local particle data
    m_molecule_order.resize(m_pdata->getMaxN());

        {
        // write out molecule list and order
        ArrayHandle<unsigned int> d_molecule_list(m_molecule_list, access_location::device, access_mode::overwrite);
        ArrayHandle<unsigned int> d_molecule_order(m_molecule_order, access_location::device, access_mode::overwrite);
        ArrayHandle<unsigned int> d_molecule_idx(m_molecule_idx, access_location::device, access_mode::read);

        m_tuner_fill->begin();
        unsigned int block_size = m_tuner_fill->getParam();

        gpu_fill_molecule_table(nptl_local,
            n_local_ptls_in_molecules,
            m_molecule_indexer,
            d_molecule_idx.data,
            d_local_molecule_tags.data,
            d_idx_sorted_by_tag.data,
            d_molecule_list.data,
            d_molecule_order.data,
            block_size,
            m_exec_conf->getCachedAllocator());

        if (m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();

        m_tuner_fill->end();
        }

    if (m_exec_conf->getNumActiveGPUs() > 1)
        {
        auto gpu_map = m_exec_conf->getGPUIds();

        for (unsigned int idev = 0; idev < m_exec_conf->getNumActiveGPUs(); ++idev)
            {
            cudaMemAdvise(m_molecule_list.get(), sizeof(unsigned int)*m_molecule_list.getNumElements(), cudaMemAdviseSetAccessedBy, gpu_map[idev]);
            cudaMemAdvise(m_molecule_length.get(), sizeof(unsigned int)*m_molecule_length.getNumElements(), cudaMemAdviseSetAccessedBy, gpu_map[idev]);
            }

        for (unsigned int idev = 0; idev < m_exec_conf->getNumActiveGPUs(); ++idev)
            {
            auto range = m_pdata->getGPUPartition().getRange(idev);
            unsigned int nelem =  range.second - range.first;

            // skip if no hint set
            if (!nelem)
                continue;

            cudaMemAdvise(m_molecule_idx.get()+range.first, sizeof(unsigned int)*nelem, cudaMemAdviseSetPreferredLocation, gpu_map[idev]);
            cudaMemPrefetchAsync(m_molecule_idx.get()+range.first, sizeof(unsigned int)*nelem, gpu_map[idev]);
            }

        CHECK_CUDA_ERROR();
        }

    if (m_prof) m_prof->pop(m_exec_conf);
    }
#endif

void MolecularForceCompute::initMolecules()
    {
    // return early if no molecules are defined
    if (!m_n_molecules_global) return;

    m_exec_conf->msg->notice(7) << "MolecularForceCompute initializing molecule table" << std::endl;

    #ifdef ENABLE_CUDA
    if (m_exec_conf->isCUDAEnabled())
        {
        initMoleculesGPU();
        return;
        }
    #endif

    if (m_prof) m_prof->push("init molecules");

    // construct local molecule table
    unsigned int nptl_local = m_pdata->getN() + m_pdata->getNGhosts();

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

    std::set<unsigned int> local_molecule_tags;

    unsigned int n_local_molecules = 0;

    std::vector<unsigned int> local_molecule_idx(nptl_local, NO_MOLECULE);

    // resize molecule lookup to size of local particle data
    m_molecule_order.resize(m_pdata->getMaxN());

    // sort local molecules by molecule tag, and inside the molecule by ptl tag
    std::map<unsigned int, std::set<unsigned int> > local_molecules_sorted;

    for (unsigned int iptl = 0; iptl < nptl_local; ++iptl)
        {
        unsigned int tag = h_tag.data[iptl];
        assert(tag < m_molecule_tag.getNumElements());

        unsigned int mol_tag = h_molecule_tag.data[tag];
        if (mol_tag == NO_MOLECULE) continue;

        auto it = local_molecules_sorted.find(mol_tag);
        if (it == local_molecules_sorted.end())
            {
            auto res = local_molecules_sorted.insert(std::make_pair(mol_tag,std::set<unsigned int>()));
            assert(res.second);
            it = res.first;
            }

        it->second.insert(tag);
        }

    n_local_molecules = local_molecules_sorted.size();

    m_exec_conf->msg->notice(7) << "MolecularForceCompute: " << n_local_molecules << " molecules" << std::endl;

    m_molecule_length.resize(n_local_molecules);

    ArrayHandle<unsigned int> h_molecule_length(m_molecule_length, access_location::host, access_mode::overwrite);

    // reset lengths
    for (unsigned int imol = 0; imol < n_local_molecules; ++imol)
        {
        h_molecule_length.data[imol] = 0;
        }

    // count molecule lengths
    unsigned int i = 0;
    for (auto it = local_molecules_sorted.begin(); it != local_molecules_sorted.end(); ++it)
        {
        h_molecule_length.data[i++] = it->second.size();
        }

    // find maximum length
    unsigned nmax = 0;
    for (unsigned int imol = 0; imol < n_local_molecules; ++imol)
        {
        if (h_molecule_length.data[imol] > nmax)
            {
            nmax = h_molecule_length.data[imol];
            }
        }

    // set up indexer
    m_molecule_indexer = Index2D(nmax, n_local_molecules);

    // resize molecule list
    m_molecule_list.resize(m_molecule_indexer.getNumElements());

    // reset lengths again
    for (unsigned int imol = 0; imol < n_local_molecules; ++imol)
        {
        h_molecule_length.data[imol] = 0;
        }

    // reset molecule order
    ArrayHandle<unsigned int> h_molecule_order(m_molecule_order, access_location::host, access_mode::overwrite);
    memset(h_molecule_order.data, 0, sizeof(unsigned int)*(m_pdata->getN() + m_pdata->getNGhosts()));

    // resize reverse-lookup
    m_molecule_idx.resize(nptl_local);

    // fill molecule list
    ArrayHandle<unsigned int> h_molecule_list(m_molecule_list, access_location::host, access_mode::overwrite);
    ArrayHandle<unsigned int> h_molecule_idx(m_molecule_idx, access_location::host, access_mode::overwrite);
    ArrayHandle<unsigned int> h_rtag(m_pdata->getRTags(), access_location::host, access_mode::read);

    // reset reverse lookup
    memset(h_molecule_idx.data, 0, sizeof(unsigned int)*nptl_local);

    unsigned int i_mol = 0;
    for (auto it_mol = local_molecules_sorted.begin(); it_mol != local_molecules_sorted.end(); ++it_mol)
        {
        for (std::set<unsigned int>::iterator it_tag = it_mol->second.begin(); it_tag != it_mol->second.end(); ++it_tag)
            {
            unsigned int n = h_molecule_length.data[i_mol]++;
            unsigned int ptl_idx = h_rtag.data[*it_tag];
            assert(ptl_idx < m_pdata->getN() + m_pdata->getNGhosts());
            h_molecule_list.data[m_molecule_indexer(n, i_mol)] = ptl_idx;
            h_molecule_idx.data[ptl_idx] = i_mol;
            h_molecule_order.data[ptl_idx] = n;
            }
        i_mol ++;
        }

    if (m_prof) m_prof->pop(m_exec_conf);
    }

void export_MolecularForceCompute(py::module& m)
    {
    py::class_< MolecularForceCompute, std::shared_ptr<MolecularForceCompute> >(m, "MolecularForceCompute", py::base<ForceConstraint>())
    .def(py::init< std::shared_ptr<SystemDefinition> >())
    ;
    }
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"

#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

const size_t kBiosDataBufferSize = 256;

static char* trim(const char* src) {
  if (src == nullptr || *src == '\0') {
    return nullptr;
  }
  char* des = nullptr;
  size_t start = 0, end = strlen(src) - 1;
  /* find the last character that is not a whitespace. */
  while (end != 0 && isspace(src[end])) {
    end--;
  }
  /* find the first character that is not a whitespace. */
  while (start < strlen(src) && isspace(src[start])) {
    start++;
  }
  if (start <= end) {
    des = static_cast<char*>(
        gpr_zalloc(sizeof(char) * (end - start + 2 /* '\0' */)));
    memcpy(des, src + start, end - start + 1);
  }
  return des;
}

namespace grpc_core {
namespace internal {

char* read_bios_file(const char* bios_file) {
  FILE* fp = fopen(bios_file, "r");
  if (!fp) {
    gpr_log(GPR_ERROR, "BIOS data file cannot be opened.");
    return nullptr;
  }
  char buf[kBiosDataBufferSize + 1];
  size_t ret = fread(buf, sizeof(char), kBiosDataBufferSize, fp);
  buf[ret] = '\0';
  char* trimmed_buf = trim(buf);
  fclose(fp);
  return trimmed_buf;
}

}  // namespace internal
}  // namespace grpc_core
<commit_msg>silent log when bios data file does not exist<commit_after>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"

#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

const size_t kBiosDataBufferSize = 256;

static char* trim(const char* src) {
  if (src == nullptr || *src == '\0') {
    return nullptr;
  }
  char* des = nullptr;
  size_t start = 0, end = strlen(src) - 1;
  /* find the last character that is not a whitespace. */
  while (end != 0 && isspace(src[end])) {
    end--;
  }
  /* find the first character that is not a whitespace. */
  while (start < strlen(src) && isspace(src[start])) {
    start++;
  }
  if (start <= end) {
    des = static_cast<char*>(
        gpr_zalloc(sizeof(char) * (end - start + 2 /* '\0' */)));
    memcpy(des, src + start, end - start + 1);
  }
  return des;
}

namespace grpc_core {
namespace internal {

char* read_bios_file(const char* bios_file) {
  FILE* fp = fopen(bios_file, "r");
  if (!fp) {
    gpr_log(GPR_INFO, "BIOS data file does not exist or cannot be opened.");
    return nullptr;
  }
  char buf[kBiosDataBufferSize + 1];
  size_t ret = fread(buf, sizeof(char), kBiosDataBufferSize, fp);
  buf[ret] = '\0';
  char* trimmed_buf = trim(buf);
  fclose(fp);
  return trimmed_buf;
}

}  // namespace internal
}  // namespace grpc_core
<|endoftext|>


<commit_before>#include <malloc.h>
#include <cstring>
#include "SystemMessagePacket.h"
#include "Poco/BinaryWriter.h"
#include "Poco/MemoryStream.h"
#include "../data/PSO2String.h"

SystemMessagePacket::SystemMessagePacket(std::string message, uint32_t messageType){
    this->message = message;
    this->messageType = messageType;
}

SystemMessagePacket::~SystemMessagePacket() {

}

PacketData SystemMessagePacket::build() {
    // Convert the sting to a PSO2String.
    Polaris::Data::PSO2String theString = Polaris::Data::CreatePSO2String(message, 0xA2, 0x78F7);
    PacketHeader header((uint32_t) (sizeof(PacketHeader) + theString.dataLength + sizeof(uint32_t)), 0x19, 0x01, 0x04, 0x00);
    PacketData data(header.length);
    data.appendData(&header, sizeof(header));
    data.appendData(&theString.magicValue, 4);
    data.appendData(theString.utf16string.data(), theString.dataLength - 4);
    return data;

}
<commit_msg>Insert message type<commit_after>#include <malloc.h>
#include <cstring>
#include "SystemMessagePacket.h"
#include "Poco/BinaryWriter.h"
#include "Poco/MemoryStream.h"
#include "../data/PSO2String.h"

SystemMessagePacket::SystemMessagePacket(std::string message, uint32_t messageType){
    this->message = message;
    this->messageType = messageType;
}

SystemMessagePacket::~SystemMessagePacket() {

}

PacketData SystemMessagePacket::build() {
    // Convert the sting to a PSO2String.
    Polaris::Data::PSO2String theString = Polaris::Data::CreatePSO2String(message, 0xA2, 0x78F7);
    PacketHeader header((uint32_t) (sizeof(PacketHeader) + theString.dataLength + sizeof(uint32_t)), 0x19, 0x01, 0x04, 0x00);
    PacketData data(header.length);
    data.appendData(&header, sizeof(header));
    data.appendData(&theString.magicValue, 4);
    data.appendData(theString.utf16string.data(), theString.dataLength - 4);
    data.appendData(&messageType, 4);
    return data;

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_utils_to_throttle.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_utils_to_throttle.H
/// @brief Sets throttles
/// TMGT will call this procedure to set the N address operations (commands)
/// allowed within a window of M DRAM clocks given the minimum dram data bus utilization.
///

// *HWP HWP Owner: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#ifndef __P9_MSS_UTILS_TO_THROTTLE__
#define __P9_MSS_UTILS_TO_THROTTLE__

#include <fapi2.H>
#include <vector>

typedef fapi2::ReturnCode (*p9_mss_utils_to_throttle_FP_t) (const
        std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCS> >&);

extern "C"
{

///
/// @brief Set the N throttle attributes for a given dram data bus utilization.
/// @param[in] i_targets vector of MCS on the same VDDR domain
/// @return FAPI2_RC_SUCCESS iff ok
/// @note throttle_per_slot will be equalized so all throttles coming out will be equal to worst case
    fapi2::ReturnCode p9_mss_utils_to_throttle( const std::vector <fapi2::Target<fapi2::TARGET_TYPE_MCS> >& i_targets );
}

#endif
<commit_msg>Cleaning up and implementing L3 eff_config_thermal<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_utils_to_throttle.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_utils_to_throttle.H
/// @brief Sets throttles
/// TMGT will call this procedure to set the N address operations (commands)
/// allowed within a window of M DRAM clocks given the minimum dram data bus utilization.
///

// *HWP HWP Owner: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP HWP Backup: Andre A. Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#ifndef __P9_MSS_UTILS_TO_THROTTLE__
#define __P9_MSS_UTILS_TO_THROTTLE__

#include <fapi2.H>
#include <vector>

typedef fapi2::ReturnCode (*p9_mss_utils_to_throttle_FP_t) (const
        std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCS> >&);

extern "C"
{

    ///
    /// @brief Sets number commands allowed within a given port databus utilization.
    /// @param[in] i_targets vector of MCS to set throttle attributes on
    /// @return FAPI2_RC_SUCCESS iff ok
    /// @note ATTR_MSS_MEM_THROTTLED_N_COMMANDS_PER_SLOT will be set to worst case of all slots passed in
    /// @note output ATTR_MSS_MEM_THROTTLED_N_COMMANDS_PER_SLOT, ATTR_MSS_MEM_THROTTLED_N_COMMANDS_PER_PORT, and ATTR_MSS_PORT_MAXPOWER
    ///
    fapi2::ReturnCode p9_mss_utils_to_throttle( const std::vector <fapi2::Target<fapi2::TARGET_TYPE_MCS> >& i_targets );
}

#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_get_poundv_bucket_attr.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///

/// @file p9_pm_get_poundv_bucket_attr.C
/// @brief Grab PM data from certain bucket in #V keyword in LRPX record
///
/// *HWP HW Owner    : N/A (This is a FW delivered function)
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : PM - Calling this function.
/// *HWP Consumed by : FSP
/// *HWP Level       : 3
///

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------
#include <p9_pm_get_poundv_bucket_attr.H>
#include <p9_pm_get_poundv_bucket.H>
#include <mvpd_access_defs.H>
#include <attribute_ids.H>

fapi2::ReturnCode p9_pm_get_poundv_bucket_attr(
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
    uint8_t* o_data)
{
    FAPI_DBG("Entering p9_pm_get_poundv_bucket_attr ....");
    uint8_t* l_prDataPtr = NULL;
    uint8_t* l_fullVpdData = NULL;
    uint8_t l_overridePresent = 0;
    uint32_t l_tempVpdSize = 0;
    uint32_t l_vpdSize = 0;
    uint8_t l_eqChipUnitPos = 0;
    uint8_t l_bucketId = 0xFF;
    uint8_t l_bucketSize = 0;
    uint32_t l_sysNestFreq = 0;
    uint32_t l_fallbackNestFreq = 0;
    fapi2::voltageBucketData_t* l_currentBucket = NULL;
    fapi2::voltageBucketData_t* l_fallbackBucket = NULL;
    uint8_t l_numMatches = 0;
    uint8_t l_numMatchesFallback = 0;
    uint16_t l_pbFreq = 0;

    fapi2::MvpdRecord lrpRecord = fapi2::MVPD_RECORD_LAST;
    //To read MVPD we will need the proc parent of the inputted EQ target
    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> l_procParent =
        i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();

    //Need to determine which LRP record to read from depending on which
    //bucket we are getting the power management data from. FapiPos will
    //tell us which LRP record to use.
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                           i_target,
                           l_eqChipUnitPos));

    FAPI_ASSERT( l_eqChipUnitPos < NUM_BUCKETS ,
                 fapi2::INVALID_EQ_CHIP_POS().
                 set_EQ_POSITION( l_eqChipUnitPos ),
                 "Invalid EQ chip unit position = 0x%X",
                 l_eqChipUnitPos);

    //The enumeration for the LRPx records are just 3 more
    //than the EQ chip unit pos. See mvpd_access_defs.H
    lrpRecord = static_cast<fapi2::MvpdRecord>(l_eqChipUnitPos +
                fapi2::MVPD_RECORD_LRP0 );

    //check if bucket num has been overriden
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM_OVERRIDE,
                           i_target,
                           l_overridePresent));

    if(l_overridePresent != 0)
    {
        //If it has been overriden then get the override
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM,
                               i_target,
                               l_bucketId));
    }
    else
    {
        //First read is to get size of vpd record, note the o_buffer is NULL
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               NULL,
                               l_tempVpdSize) );

        //save off the actual vpd size
        l_vpdSize = l_tempVpdSize;
        //Allocate memory for vpd data
        l_fullVpdData = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

        //Second read is to get data of vpd record
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               l_fullVpdData,
                               l_tempVpdSize) );

        //Version 2:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x33 byte
        //bucket b: 0x33 byte
        //bucket c: 0x33 byte
        //bucket d: 0x33 byte
        //bucket e: 0x33 byte
        //bucket f: 0x33 byte
        if( *l_fullVpdData == POUNDV_VERSION_2)
        {
            //Set the size of the bucket
            l_bucketSize = VERSION_2_BUCKET_SIZE;

            //Reset VPD size because we want to find size of another VPD record
            l_tempVpdSize = 0;

            //First read is to get size of vpd record, note the o_buffer is NULL
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   NULL,
                                   l_tempVpdSize) );

            l_prDataPtr = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

            //Second read is to get data of vpd record
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   l_prDataPtr,
                                   l_tempVpdSize) );

            //Bucket ID is byte[4] of the PR keyword
            memcpy(&l_bucketId, (l_prDataPtr + 4), sizeof(uint8_t));

        }
        //Version 3:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x3D byte
        //bucket b: 0x3D byte
        //bucket c: 0x3D byte
        //bucket d: 0x3D byte
        //bucket e: 0x3D byte
        //bucket f: 0x3D byte
        else if( *l_fullVpdData == POUNDV_VERSION_3 )
        {
            // Set the size of the bucket
            l_bucketSize = VERSION_3_BUCKET_SIZE;

            //Save off some FFDC data about the #V data itself
            uint16_t l_bucketNestFreqs[NUM_BUCKETS] = { 0, 0, 0, 0, 0, 0 };

            // Version 3 uses the nest frequency to choose the bucket Id
            // get the system target to find the NEST_FREQ_MHZ
            fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> l_sysParent;

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ,
                                   l_sysParent,
                                   l_sysNestFreq));
            //cast the voltage data into an array of buckets
            fapi2::voltageBucketData_t* l_buckets = reinterpret_cast
                                                    <fapi2::voltageBucketData_t*>
                                                    (l_fullVpdData + POUNDV_BUCKET_OFFSET);

            //see if we have a fall-back frequency to use if we don't
            // get a match
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ_POUNDV_FALLBACK,
                                   l_sysParent,
                                   l_fallbackNestFreq));

            for(int i = 0; i < NUM_BUCKETS; i++)
            {
#ifndef _BIG_ENDIAN
                l_pbFreq = ( (((l_buckets[i].pbFreq) >> 8) & 0x00FF) | (((l_buckets[i].pbFreq) << 8) & 0xFF00) );
#else
                l_pbFreq = l_buckets[i].pbFreq;
#endif

                if(l_pbFreq == l_sysNestFreq)
                {
                    l_numMatches++;

                    if(l_numMatches > 1)
                    {
                        FAPI_ERR("p9_pm_get_poundv_bucket_attr::"
                                 " Multiple buckets (%d) reporting the same nest frequency"
                                 " Bucket Nest = %d Bucket ID = %d, First Bucket = %d",
                                 l_numMatches,
                                 l_pbFreq,
                                 (i + 1),
                                 l_currentBucket);

                    }
                    else
                    {
                        l_currentBucket = &l_buckets[i];
                    }
                }
                else if(l_pbFreq == l_fallbackNestFreq)
                {
                    l_numMatchesFallback++;

                    if(l_numMatchesFallback > 1)
                    {
                        FAPI_ERR("p9_pm_get_poundv_bucket_attr::"
                                 " Multiple buckets (%d) reporting the same nest frequency"
                                 " Fallback Nest = %d Bucket ID = %d, First Bucket = %d",
                                 l_numMatchesFallback,
                                 l_fallbackNestFreq,
                                 (i + 1),
                                 l_fallbackBucket);

                    }
                    else
                    {
                        l_fallbackBucket = &l_buckets[i];
                    }
                }

                //save FFDC in case we fail
                l_bucketNestFreqs[i] = l_pbFreq;
            }

            if(l_numMatches == 1)
            {
                l_bucketId = l_currentBucket->bucketId;
            }
            else if(l_numMatchesFallback == 1)
            {
                FAPI_ERR("p9_pm_get_poundv_bucket_attr::Invalid number of matching "
                         "nest freqs found for PBFreq=%d. Matches found = %d. But "
                         "did find a fallback match for Freq=%d",
                         l_sysNestFreq, l_numMatches, l_fallbackNestFreq );
                l_bucketId = l_fallbackBucket->bucketId;
            }
            else
            {

                FAPI_ERR("p9_pm_get_poundv_bucket_attr::Invalid number of matching "
                         "nest freqs found for PBFreq=%d. Matches found = %d",
                         l_sysNestFreq, l_numMatches );
                FAPI_ASSERT(false,
                            fapi2::INVALID_MATCHING_FREQ_NUMBER().
                            set_EQ_TARGET(i_target).
                            set_MATCHES_FOUND(l_numMatches).
                            set_DESIRED_FREQPB(l_sysNestFreq).
                            set_LRPREC(lrpRecord).
                            set_BUCKETA_FREQPB(l_bucketNestFreqs[0]).
                            set_BUCKETB_FREQPB(l_bucketNestFreqs[1]).
                            set_BUCKETC_FREQPB(l_bucketNestFreqs[2]).
                            set_BUCKETD_FREQPB(l_bucketNestFreqs[3]).
                            set_BUCKETE_FREQPB(l_bucketNestFreqs[4]).
                            set_BUCKETF_FREQPB(l_bucketNestFreqs[5]),
                            "Matches found is NOT 1" );
            }
        }
        else
        {
            FAPI_ASSERT( false,
                         fapi2::INVALID_POUNDV_VERSION()
                         .set_EQ_TARGET(i_target)
                         .set_POUNDV_VERSION(*l_fullVpdData),
                         "p9_pm_get_poundv_bucket_attr::Invalid #V record version: 0x%x",
                         *l_fullVpdData);
        }

        // This assert ensures the size of the calculated data is correct
        FAPI_ASSERT(l_vpdSize - POUNDV_BUCKET_OFFSET - ((l_bucketId - 1) *
                    l_bucketSize) >= l_bucketSize,
                    fapi2::BAD_VPD_READ()
                    .set_EQ_TARGET(i_target)
                    .set_EXPECTED_SIZE(sizeof(l_bucketSize))
                    .set_ACTUAL_SIZE(l_vpdSize - POUNDV_BUCKET_OFFSET -
                                     ((l_bucketId - 1) * l_bucketSize)),
                    "#V data read was too small!" );

    }// else no override

    // Ensure we got a valid bucket id
    // NOTE: Bucket IDs range from 1-6
    FAPI_ASSERT( (l_bucketId <= NUM_BUCKETS) && (l_bucketId != 0),
                 fapi2::INVALID_BUCKET_ID()
                 .set_EQ_TARGET(i_target)
                 .set_BUCKET_ID(l_bucketId),
                 "Invalid Bucket Id = %d",
                 l_bucketId );

    // Use the selected bucket id to populate the output data
    memcpy(o_data,
           l_fullVpdData + POUNDV_BUCKET_OFFSET + (l_bucketId - 1) * l_bucketSize,
           l_bucketSize);

fapi_try_exit:

    if(l_fullVpdData != NULL)
    {
        free(l_fullVpdData);
        l_fullVpdData = NULL;
    }

    if(l_prDataPtr != NULL)
    {
        free(l_prDataPtr);
        l_prDataPtr = NULL;
    }

    FAPI_DBG("Exiting p9_pm_get_poundv_bucket_attr ....");

    return fapi2::current_err;
}
<commit_msg>Remove distracting error message for fallback #V freq<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_get_poundv_bucket_attr.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///

/// @file p9_pm_get_poundv_bucket_attr.C
/// @brief Grab PM data from certain bucket in #V keyword in LRPX record
///
/// *HWP HW Owner    : N/A (This is a FW delivered function)
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : PM - Calling this function.
/// *HWP Consumed by : FSP
/// *HWP Level       : 3
///

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------
#include <p9_pm_get_poundv_bucket_attr.H>
#include <p9_pm_get_poundv_bucket.H>
#include <mvpd_access_defs.H>
#include <attribute_ids.H>

fapi2::ReturnCode p9_pm_get_poundv_bucket_attr(
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
    uint8_t* o_data)
{
    FAPI_DBG("Entering p9_pm_get_poundv_bucket_attr ....");
    uint8_t* l_prDataPtr = NULL;
    uint8_t* l_fullVpdData = NULL;
    uint8_t l_overridePresent = 0;
    uint32_t l_tempVpdSize = 0;
    uint32_t l_vpdSize = 0;
    uint8_t l_eqChipUnitPos = 0;
    uint8_t l_bucketId = 0xFF;
    uint8_t l_bucketSize = 0;
    uint32_t l_sysNestFreq = 0;
    uint32_t l_fallbackNestFreq = 0;
    fapi2::voltageBucketData_t* l_currentBucket = NULL;
    fapi2::voltageBucketData_t* l_fallbackBucket = NULL;
    uint8_t l_numMatches = 0;
    uint8_t l_numMatchesFallback = 0;
    uint16_t l_pbFreq = 0;

    fapi2::MvpdRecord lrpRecord = fapi2::MVPD_RECORD_LAST;
    //To read MVPD we will need the proc parent of the inputted EQ target
    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> l_procParent =
        i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();

    //Need to determine which LRP record to read from depending on which
    //bucket we are getting the power management data from. FapiPos will
    //tell us which LRP record to use.
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                           i_target,
                           l_eqChipUnitPos));

    FAPI_ASSERT( l_eqChipUnitPos < NUM_BUCKETS ,
                 fapi2::INVALID_EQ_CHIP_POS().
                 set_EQ_POSITION( l_eqChipUnitPos ),
                 "Invalid EQ chip unit position = 0x%X",
                 l_eqChipUnitPos);

    //The enumeration for the LRPx records are just 3 more
    //than the EQ chip unit pos. See mvpd_access_defs.H
    lrpRecord = static_cast<fapi2::MvpdRecord>(l_eqChipUnitPos +
                fapi2::MVPD_RECORD_LRP0 );

    //check if bucket num has been overriden
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM_OVERRIDE,
                           i_target,
                           l_overridePresent));

    if(l_overridePresent != 0)
    {
        //If it has been overriden then get the override
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM,
                               i_target,
                               l_bucketId));
    }
    else
    {
        //First read is to get size of vpd record, note the o_buffer is NULL
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               NULL,
                               l_tempVpdSize) );

        //save off the actual vpd size
        l_vpdSize = l_tempVpdSize;
        //Allocate memory for vpd data
        l_fullVpdData = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

        //Second read is to get data of vpd record
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               l_fullVpdData,
                               l_tempVpdSize) );

        //Version 2:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x33 byte
        //bucket b: 0x33 byte
        //bucket c: 0x33 byte
        //bucket d: 0x33 byte
        //bucket e: 0x33 byte
        //bucket f: 0x33 byte
        if( *l_fullVpdData == POUNDV_VERSION_2)
        {
            //Set the size of the bucket
            l_bucketSize = VERSION_2_BUCKET_SIZE;

            //Reset VPD size because we want to find size of another VPD record
            l_tempVpdSize = 0;

            //First read is to get size of vpd record, note the o_buffer is NULL
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   NULL,
                                   l_tempVpdSize) );

            l_prDataPtr = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

            //Second read is to get data of vpd record
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   l_prDataPtr,
                                   l_tempVpdSize) );

            //Bucket ID is byte[4] of the PR keyword
            memcpy(&l_bucketId, (l_prDataPtr + 4), sizeof(uint8_t));

        }
        //Version 3:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x3D byte
        //bucket b: 0x3D byte
        //bucket c: 0x3D byte
        //bucket d: 0x3D byte
        //bucket e: 0x3D byte
        //bucket f: 0x3D byte
        else if( *l_fullVpdData == POUNDV_VERSION_3 )
        {
            // Set the size of the bucket
            l_bucketSize = VERSION_3_BUCKET_SIZE;

            //Save off some FFDC data about the #V data itself
            uint16_t l_bucketNestFreqs[NUM_BUCKETS] = { 0, 0, 0, 0, 0, 0 };

            // Version 3 uses the nest frequency to choose the bucket Id
            // get the system target to find the NEST_FREQ_MHZ
            fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> l_sysParent;

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ,
                                   l_sysParent,
                                   l_sysNestFreq));
            //cast the voltage data into an array of buckets
            fapi2::voltageBucketData_t* l_buckets = reinterpret_cast
                                                    <fapi2::voltageBucketData_t*>
                                                    (l_fullVpdData + POUNDV_BUCKET_OFFSET);

            //see if we have a fall-back frequency to use if we don't
            // get a match
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ_POUNDV_FALLBACK,
                                   l_sysParent,
                                   l_fallbackNestFreq));

            for(int i = 0; i < NUM_BUCKETS; i++)
            {
#ifndef _BIG_ENDIAN
                l_pbFreq = ( (((l_buckets[i].pbFreq) >> 8) & 0x00FF) | (((l_buckets[i].pbFreq) << 8) & 0xFF00) );
#else
                l_pbFreq = l_buckets[i].pbFreq;
#endif

                if(l_pbFreq == l_sysNestFreq)
                {
                    l_numMatches++;

                    if(l_numMatches > 1)
                    {
                        FAPI_ERR("p9_pm_get_poundv_bucket_attr::"
                                 " Multiple buckets (%d) reporting the same nest frequency"
                                 " Bucket Nest = %d Bucket ID = %d, First Bucket = %d",
                                 l_numMatches,
                                 l_pbFreq,
                                 (i + 1),
                                 l_currentBucket);

                    }
                    else
                    {
                        l_currentBucket = &l_buckets[i];
                    }
                }
                else if( (l_pbFreq == l_fallbackNestFreq)
                         && (l_pbFreq != 0) )
                {
                    l_numMatchesFallback++;

                    if(l_numMatchesFallback > 1)
                    {
                        FAPI_INF("p9_pm_get_poundv_bucket_attr::"
                                 " Multiple buckets (%d) reporting the same nest frequency"
                                 " Fallback Nest = %d Bucket ID = %d, First Bucket = %d",
                                 l_numMatchesFallback,
                                 l_fallbackNestFreq,
                                 (i + 1),
                                 l_fallbackBucket);

                    }
                    else
                    {
                        l_fallbackBucket = &l_buckets[i];
                    }
                }

                //save FFDC in case we fail
                l_bucketNestFreqs[i] = l_pbFreq;
            }

            if(l_numMatches == 1)
            {
                l_bucketId = l_currentBucket->bucketId;
            }
            else if(l_numMatchesFallback == 1)
            {
                FAPI_ERR("p9_pm_get_poundv_bucket_attr::Invalid number of matching "
                         "nest freqs found for PBFreq=%d. Matches found = %d. But "
                         "did find a fallback match for Freq=%d",
                         l_sysNestFreq, l_numMatches, l_fallbackNestFreq );
                l_bucketId = l_fallbackBucket->bucketId;
            }
            else
            {

                FAPI_ERR("p9_pm_get_poundv_bucket_attr::Invalid number of matching "
                         "nest freqs found for PBFreq=%d. Matches found = %d",
                         l_sysNestFreq, l_numMatches );
                FAPI_ASSERT(false,
                            fapi2::INVALID_MATCHING_FREQ_NUMBER().
                            set_EQ_TARGET(i_target).
                            set_MATCHES_FOUND(l_numMatches).
                            set_DESIRED_FREQPB(l_sysNestFreq).
                            set_LRPREC(lrpRecord).
                            set_BUCKETA_FREQPB(l_bucketNestFreqs[0]).
                            set_BUCKETB_FREQPB(l_bucketNestFreqs[1]).
                            set_BUCKETC_FREQPB(l_bucketNestFreqs[2]).
                            set_BUCKETD_FREQPB(l_bucketNestFreqs[3]).
                            set_BUCKETE_FREQPB(l_bucketNestFreqs[4]).
                            set_BUCKETF_FREQPB(l_bucketNestFreqs[5]),
                            "Matches found is NOT 1" );
            }
        }
        else
        {
            FAPI_ASSERT( false,
                         fapi2::INVALID_POUNDV_VERSION()
                         .set_EQ_TARGET(i_target)
                         .set_POUNDV_VERSION(*l_fullVpdData),
                         "p9_pm_get_poundv_bucket_attr::Invalid #V record version: 0x%x",
                         *l_fullVpdData);
        }

        // This assert ensures the size of the calculated data is correct
        FAPI_ASSERT(l_vpdSize - POUNDV_BUCKET_OFFSET - ((l_bucketId - 1) *
                    l_bucketSize) >= l_bucketSize,
                    fapi2::BAD_VPD_READ()
                    .set_EQ_TARGET(i_target)
                    .set_EXPECTED_SIZE(sizeof(l_bucketSize))
                    .set_ACTUAL_SIZE(l_vpdSize - POUNDV_BUCKET_OFFSET -
                                     ((l_bucketId - 1) * l_bucketSize)),
                    "#V data read was too small!" );

    }// else no override

    // Ensure we got a valid bucket id
    // NOTE: Bucket IDs range from 1-6
    FAPI_ASSERT( (l_bucketId <= NUM_BUCKETS) && (l_bucketId != 0),
                 fapi2::INVALID_BUCKET_ID()
                 .set_EQ_TARGET(i_target)
                 .set_BUCKET_ID(l_bucketId),
                 "Invalid Bucket Id = %d",
                 l_bucketId );

    // Use the selected bucket id to populate the output data
    memcpy(o_data,
           l_fullVpdData + POUNDV_BUCKET_OFFSET + (l_bucketId - 1) * l_bucketSize,
           l_bucketSize);

fapi_try_exit:

    if(l_fullVpdData != NULL)
    {
        free(l_fullVpdData);
        l_fullVpdData = NULL;
    }

    if(l_prDataPtr != NULL)
    {
        free(l_prDataPtr);
        l_prDataPtr = NULL;
    }

    FAPI_DBG("Exiting p9_pm_get_poundv_bucket_attr ....");

    return fapi2::current_err;
}
<|endoftext|>