<commit_before>//---------------------------------------------------------------------------
// hexanoise/generator_opencl.cpp
//
// Copyright 2014, nocte@hippie.nu            Released under the MIT License.
//---------------------------------------------------------------------------

#include "generator_opencl.hpp"

#include <iostream>
#include <cmath>
#include <fstream>
#include <stdexcept>
#include "node.hpp"

#ifndef OPENCL_OCTAVES_LIMIT
# define OPENCL_OCTAVES_LIMIT 16
#endif

namespace hexa {
namespace noise {

generator_opencl::generator_opencl (const generator_context& ctx,
                                    cl::Context& opencl_context,
                                    cl::Device&  opencl_device,
                                    const node& n,
                                    const std::string& opencl_file)
    : generator_i(ctx)
    , count_(1)
    , context_(opencl_context)
    , queue_ (opencl_context, opencl_device)
{
    std::string body (co(n));

    std::ifstream file (opencl_file.c_str(), std::ios::binary);
    if (!file)
        throw std::runtime_error("cannot open OpenCL file " + opencl_file);

    file.seekg(0, std::ios::end);
    main_.resize(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read(&main_[0], main_.size());
    file.close();

    main_ += "\n";
    for (auto& p : functions_)
    {
        main_ += p;
        main_ += "\n\n";
    }
    main_ += "\n" \
    "__kernel void noisemain(\n" \
    "  __global double* output, const double2 start, const double2 step)\n" \
    "{\n"\
    "    int2 coord = (int2)(get_global_id(0), get_global_id(1));\n"\
    "    int  sizex = get_global_size(0);\n"\
    "    double2 p = mad(step, (double2)(coord.x, coord.y), start);\n" \
    "    output[coord.y * sizex + coord.x] = ";

    main_ += body;
    main_ += ";\n}\n";

    std::vector<cl::Device> device_vec;
    device_vec.emplace_back(opencl_device);

    cl::Program::Sources sources (1, { main_.c_str(), main_.size() });
    program_ = cl::Program(opencl_context, sources);
    try
    {
        program_.build(device_vec);
    }
    catch (cl::Error&)
    {
        std::cerr << program_.getBuildInfo<CL_PROGRAM_BUILD_LOG>(opencl_device) << std::endl;
        throw;
    }

    kernel_ = cl::Kernel(program_, "noisemain");
}

std::vector<double>
generator_opencl::run (const glm::dvec2& corner,
                       const glm::dvec2& step,
                       const glm::ivec2& count)
{
    unsigned int width (count.x), height (count.y);

    std::vector<double> result (width * height);
    cl::Buffer output (context_, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
                       result.size() * sizeof(double),
                       &result[0]);

    kernel_.setArg(0, output);
    kernel_.setArg(1, sizeof(corner), (void*)&corner);
    kernel_.setArg(2, sizeof(step),   (void*)&step);

    auto memobj (queue_.enqueueMapBuffer(output, true, CL_MAP_WRITE, 0,
                                         result.size() * sizeof(double)));
    queue_.enqueueNDRangeKernel(kernel_, cl::NullRange, {width, height}, cl::NullRange);
    queue_.enqueueUnmapMemObject(output, memobj);

    return result;
}

std::string generator_opencl::pl (const node& n)
{
    std::string result ("(");
    for (auto i (n.input.begin()); i != n.input.end(); )
    {
        result += co(*i);
        ++i;
        if (i != n.input.end())
            result.push_back(',');
    }
    result += ')';
    return result;
}

std::string generator_opencl::co (const node& n)
{
    switch (n.type)
    {
    case node::entry_point:     return "p";
    case node::const_var:       return std::to_string(n.aux_var);
    case node::const_bool:      return std::to_string(n.aux_bool);
    case node::const_str:       throw std::runtime_error("string encountered");

    case node::rotate:          return "p_rotate" + pl(n);
    case node::scale:           return "("+co(n.input[0])+"/"+co(n.input[1])+")";
    case node::shift:           return "("+co(n.input[0])+"+"+co(n.input[1])+")";
    case node::swap:            return "p_swap" + pl(n);

    case node::map:
    {
        std::string func_name ("p_map" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double2 " << func_name << " (const double2 p) { return (double2)("
        << co(n.input[1]) << ", "
        << co(n.input[2]) << "); }" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "("+ co(n.input[0]) + ")";
    }

    case node::turbulence:
    {
        std::string func_name ("p_map" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double2 " << func_name << " (const double2 p) { return (double2)("
        << "p.x+(" << co(n.input[1]) << "), "
        << "p.y+(" << co(n.input[2]) << ")); }" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "("+ co(n.input[0]) + ")";
    }

    case node::worley:
    {
        std::string func_name ("p_worley" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double " << func_name << " (const double2 q, uint seed) { "
        << "  double2 p = p_worley(q, seed);"
        << "  return " << co(n.input[1]) << "; }" << std::endl;

        functions_.emplace_back(func_body.str());
        return func_name + "("+co(n.input[0])+ ","+co(n.input[2])+")";
    }

    case node::voronoi:
    {
        std::string func_name ("p_voronoi" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double " << func_name << " (const double2 q, uint seed) { "
        << "  double2 p = p_voronoi(q, seed);"
        << "  return " << co(n.input[1]) << "; }" << std::endl;

        functions_.emplace_back(func_body.str());
        return func_name + "("+co(n.input[0])+ ","+co(n.input[2])+")";
    }

    case node::angle:           return "p_angle" + pl(n);
    case node::chebyshev:       return "p_chebyshev" + pl(n);
    case node::checkerboard:    return "p_checkerboard" + pl(n);
    case node::distance:        return "length" + pl(n);
    case node::manhattan:       return "p_manhattan" + pl(n);
    case node::perlin:          return "p_perlin" + pl(n);
    case node::x:               return co(n.input[0])+".x";
    case node::y:               return co(n.input[0])+".y";

    case node::add:             return "("+co(n.input[0])+"+"+co(n.input[1])+")";
    case node::sub:             return "("+co(n.input[0])+"-"+co(n.input[1])+")";
    case node::mul:             return "("+co(n.input[0])+"*"+co(n.input[1])+")";
    case node::div:             return "("+co(n.input[0])+"/"+co(n.input[1])+")";

    case node::abs:             return "fabs" + pl(n);
    case node::blend:           return "p_blend" + pl(n);
    case node::cos:             return "cospi" + pl(n);
    case node::min:             return "fmin" + pl(n);
    case node::max:             return "fmax" + pl(n);
    case node::neg:             return "-" + co(n.input[0]);

    case node::pow:
    {
        if (n.input[1].is_const)
        {
            double exp (std::floor(n.input[1].aux_var));
            if (std::abs(exp - n.input[1].aux_var) < 1e-9)
                return "pown("+co(n.input[0])+","+std::to_string((int)exp)+")";
        }
        return "pow"+pl(n);
    }

    case node::saw:             return "p_saw" + pl(n);
    case node::sin:             return "sinpi" + pl(n);
    case node::sqrt:            return "sqrt" + pl(n);
    case node::tan:             return "tanpi" + pl(n);

    case node::band:            return co(n.input[0])+"&&"+co(n.input[1]);
    case node::bor:             return co(n.input[0])+"||"+co(n.input[1]);
    case node::bxor:            return co(n.input[0])+"^^"+co(n.input[1]);
    case node::bnot:            return "!"+co(n.input[0]);

    case node::is_equal:        return co(n.input[0])+"=="+co(n.input[1]);
    case node::is_greaterthan:  return co(n.input[0])+">"+co(n.input[1]);
    case node::is_gte:          return co(n.input[0])+">="+co(n.input[1]);
    case node::is_lessthan:     return co(n.input[0])+"<"+co(n.input[1]);
    case node::is_lte:          return co(n.input[0])+"<="+co(n.input[1]);

    case node::is_in_circle:    return "p_is_in_circle" + pl(n);
    case node::is_in_rectangle: return "p_is_in_rectangle" + pl(n);

    case node::then_else:
        return "("+co(n.input[0])+")?("+co(n.input[1])+"):("+co(n.input[2])+")";

    case node::fractal:
    {
        assert(n.input.size() == 5);
        if (!n.input[2].is_const)
            throw std::runtime_error("fractal octave count must be a constexpr");

        int octaves (std::min<int>(n.input[2].aux_var, OPENCL_OCTAVES_LIMIT));

        std::string func_name ("p_fractal_" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "double " << func_name << " (double2 p, const double lac, const double per) {"
        << "double result = 0.0; double div = 0.0; double step = 1.0;"
        << "for(int i = 0; i < " << octaves << "; ++i)"
        << "{"
        << "  result += " << co(n.input[1]) << " * step;"
        << "  div += step;"
        << "  step *= lac;"
        << "  p *= per;"
        << "}"
        << "return result / div;"
        << "}";

        functions_.emplace_back(func_body.str());

        return func_name + "("
               + co(n.input[0]) + "," + co(n.input[3]) + ","
               + co(n.input[4]) + ")";
    }

    case node::lambda_:
    {
        assert(n.input.size() == 2);
        std::string func_name ("p_lambda_" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "double " << func_name << " (double2 p) {"
        << "return " << co(n.input[1]) << ";}" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name +"("+ co(n.input[0])+")";
    }

    case node::external_:
        throw std::runtime_error("OpenCL @external not implemented yet");

    case node::simplex:
        throw std::runtime_error("OpenCL simplex not implemented yet");

    case node::curve_linear:
        throw std::runtime_error("OpenCL curve_linear not implemented yet");

    case node::curve_spline:
        throw std::runtime_error("OpenCL curve_spline not implemented yet");

    case node::png_lookup:
        throw std::runtime_error("OpenCL png_lookup not implemented yet");

    default:
        throw std::runtime_error("function not implemented in OpenCL yet");
    }

    return std::string();
}

}} // namespace hexa::noise
<commit_msg>Wait for kernel to finish before returning<commit_after>//---------------------------------------------------------------------------
// hexanoise/generator_opencl.cpp
//
// Copyright 2014, nocte@hippie.nu            Released under the MIT License.
//---------------------------------------------------------------------------

#include "generator_opencl.hpp"

#include <iostream>
#include <cmath>
#include <fstream>
#include <stdexcept>
#include "node.hpp"

#ifndef OPENCL_OCTAVES_LIMIT
# define OPENCL_OCTAVES_LIMIT 16
#endif

namespace hexa {
namespace noise {

generator_opencl::generator_opencl (const generator_context& ctx,
                                    cl::Context& opencl_context,
                                    cl::Device&  opencl_device,
                                    const node& n,
                                    const std::string& opencl_file)
    : generator_i(ctx)
    , count_(1)
    , context_(opencl_context)
    , queue_ (opencl_context, opencl_device)
{
    std::string body (co(n));

    std::ifstream file (opencl_file.c_str(), std::ios::binary);
    if (!file)
        throw std::runtime_error("cannot open OpenCL file " + opencl_file);

    file.seekg(0, std::ios::end);
    main_.resize(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read(&main_[0], main_.size());
    file.close();

    main_ += "\n";
    for (auto& p : functions_)
    {
        main_ += p;
        main_ += "\n\n";
    }
    main_ += "\n" \
    "__kernel void noisemain(\n" \
    "  __global double* output, const double2 start, const double2 step)\n" \
    "{\n"\
    "    int2 coord = (int2)(get_global_id(0), get_global_id(1));\n"\
    "    int  sizex = get_global_size(0);\n"\
    "    double2 p = mad(step, (double2)(coord.x, coord.y), start);\n" \
    "    output[coord.y * sizex + coord.x] = ";

    main_ += body;
    main_ += ";\n}\n";

    std::vector<cl::Device> device_vec;
    device_vec.emplace_back(opencl_device);

    cl::Program::Sources sources (1, { main_.c_str(), main_.size() });
    program_ = cl::Program(opencl_context, sources);
    try
    {
        program_.build(device_vec);
    }
    catch (cl::Error&)
    {
        std::cerr << program_.getBuildInfo<CL_PROGRAM_BUILD_LOG>(opencl_device) << std::endl;
        throw;
    }

    kernel_ = cl::Kernel(program_, "noisemain");
}

std::vector<double>
generator_opencl::run (const glm::dvec2& corner,
                       const glm::dvec2& step,
                       const glm::ivec2& count)
{
    unsigned int width (count.x), height (count.y);

    std::vector<double> result (width * height);
    cl::Buffer output (context_, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
                       result.size() * sizeof(double),
                       &result[0]);

    kernel_.setArg(0, output);
    kernel_.setArg(1, sizeof(corner), (void*)&corner);
    kernel_.setArg(2, sizeof(step),   (void*)&step);

    auto memobj (queue_.enqueueMapBuffer(output, true, CL_MAP_WRITE, 0,
                                         result.size() * sizeof(double)));

    cl::Event ev;

    queue_.enqueueNDRangeKernel(kernel_, cl::NullRange, {width, height}, cl::NullRange,
                                nullptr, &ev);
    queue_.enqueueUnmapMemObject(output, memobj);
    ev.wait();

    return result;
}

std::string generator_opencl::pl (const node& n)
{
    std::string result ("(");
    for (auto i (n.input.begin()); i != n.input.end(); )
    {
        result += co(*i);
        ++i;
        if (i != n.input.end())
            result.push_back(',');
    }
    result += ')';
    return result;
}

std::string generator_opencl::co (const node& n)
{
    switch (n.type)
    {
    case node::entry_point:     return "p";
    case node::const_var:       return std::to_string(n.aux_var);
    case node::const_bool:      return std::to_string(n.aux_bool);
    case node::const_str:       throw std::runtime_error("string encountered");

    case node::rotate:          return "p_rotate" + pl(n);
    case node::scale:           return "("+co(n.input[0])+"/"+co(n.input[1])+")";
    case node::shift:           return "("+co(n.input[0])+"+"+co(n.input[1])+")";
    case node::swap:            return "p_swap" + pl(n);

    case node::map:
    {
        std::string func_name ("p_map" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double2 " << func_name << " (const double2 p) { return (double2)("
        << co(n.input[1]) << ", "
        << co(n.input[2]) << "); }" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "("+ co(n.input[0]) + ")";
    }

    case node::turbulence:
    {
        std::string func_name ("p_map" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double2 " << func_name << " (const double2 p) { return (double2)("
        << "p.x+(" << co(n.input[1]) << "), "
        << "p.y+(" << co(n.input[2]) << ")); }" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "("+ co(n.input[0]) + ")";
    }

    case node::worley:
    {
        std::string func_name ("p_worley" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double " << func_name << " (const double2 q, uint seed) { "
        << "  double2 p = p_worley(q, seed);"
        << "  return " << co(n.input[1]) << "; }" << std::endl;

        functions_.emplace_back(func_body.str());
        return func_name + "("+co(n.input[0])+ ","+co(n.input[2])+")";
    }

    case node::voronoi:
    {
        std::string func_name ("p_voronoi" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "inline double " << func_name << " (const double2 q, uint seed) { "
        << "  double2 p = p_voronoi(q, seed);"
        << "  return " << co(n.input[1]) << "; }" << std::endl;

        functions_.emplace_back(func_body.str());
        return func_name + "("+co(n.input[0])+ ","+co(n.input[2])+")";
    }

    case node::angle:           return "p_angle" + pl(n);
    case node::chebyshev:       return "p_chebyshev" + pl(n);
    case node::checkerboard:    return "p_checkerboard" + pl(n);
    case node::distance:        return "length" + pl(n);
    case node::manhattan:       return "p_manhattan" + pl(n);
    case node::perlin:          return "p_perlin" + pl(n);
    case node::x:               return co(n.input[0])+".x";
    case node::y:               return co(n.input[0])+".y";

    case node::add:             return "("+co(n.input[0])+"+"+co(n.input[1])+")";
    case node::sub:             return "("+co(n.input[0])+"-"+co(n.input[1])+")";
    case node::mul:             return "("+co(n.input[0])+"*"+co(n.input[1])+")";
    case node::div:             return "("+co(n.input[0])+"/"+co(n.input[1])+")";

    case node::abs:             return "fabs" + pl(n);
    case node::blend:           return "p_blend" + pl(n);
    case node::cos:             return "cospi" + pl(n);
    case node::min:             return "fmin" + pl(n);
    case node::max:             return "fmax" + pl(n);
    case node::neg:             return "-" + co(n.input[0]);

    case node::pow:
    {
        if (n.input[1].is_const)
        {
            double exp (std::floor(n.input[1].aux_var));
            if (std::abs(exp - n.input[1].aux_var) < 1e-9)
                return "pown("+co(n.input[0])+","+std::to_string((int)exp)+")";
        }
        return "pow"+pl(n);
    }

    case node::saw:             return "p_saw" + pl(n);
    case node::sin:             return "sinpi" + pl(n);
    case node::sqrt:            return "sqrt" + pl(n);
    case node::tan:             return "tanpi" + pl(n);

    case node::band:            return co(n.input[0])+"&&"+co(n.input[1]);
    case node::bor:             return co(n.input[0])+"||"+co(n.input[1]);
    case node::bxor:            return co(n.input[0])+"^^"+co(n.input[1]);
    case node::bnot:            return "!"+co(n.input[0]);

    case node::is_equal:        return co(n.input[0])+"=="+co(n.input[1]);
    case node::is_greaterthan:  return co(n.input[0])+">"+co(n.input[1]);
    case node::is_gte:          return co(n.input[0])+">="+co(n.input[1]);
    case node::is_lessthan:     return co(n.input[0])+"<"+co(n.input[1]);
    case node::is_lte:          return co(n.input[0])+"<="+co(n.input[1]);

    case node::is_in_circle:    return "p_is_in_circle" + pl(n);
    case node::is_in_rectangle: return "p_is_in_rectangle" + pl(n);

    case node::then_else:
        return "("+co(n.input[0])+")?("+co(n.input[1])+"):("+co(n.input[2])+")";

    case node::fractal:
    {
        assert(n.input.size() == 5);
        if (!n.input[2].is_const)
            throw std::runtime_error("fractal octave count must be a constexpr");

        int octaves (std::min<int>(n.input[2].aux_var, OPENCL_OCTAVES_LIMIT));

        std::string func_name ("p_fractal_" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "double " << func_name << " (double2 p, const double lac, const double per) {"
        << "double result = 0.0; double div = 0.0; double step = 1.0;"
        << "for(int i = 0; i < " << octaves << "; ++i)"
        << "{"
        << "  result += " << co(n.input[1]) << " * step;"
        << "  div += step;"
        << "  step *= lac;"
        << "  p *= per;"
        << "}"
        << "return result / div;"
        << "}";

        functions_.emplace_back(func_body.str());

        return func_name + "("
               + co(n.input[0]) + "," + co(n.input[3]) + ","
               + co(n.input[4]) + ")";
    }

    case node::lambda_:
    {
        assert(n.input.size() == 2);
        std::string func_name ("p_lambda_" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
        << "double " << func_name << " (double2 p) {"
        << "return " << co(n.input[1]) << ";}" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name +"("+ co(n.input[0])+")";
    }

    case node::external_:
        throw std::runtime_error("OpenCL @external not implemented yet");

    case node::simplex:
        throw std::runtime_error("OpenCL simplex not implemented yet");

    case node::curve_linear:
        throw std::runtime_error("OpenCL curve_linear not implemented yet");

    case node::curve_spline:
        throw std::runtime_error("OpenCL curve_spline not implemented yet");

    case node::png_lookup:
        throw std::runtime_error("OpenCL png_lookup not implemented yet");

    default:
        throw std::runtime_error("function not implemented in OpenCL yet");
    }

    return std::string();
}

}} // namespace hexa::noise
<|endoftext|>


<commit_before>#include "frost.h"
#include "forecast_time.h"
#include "level.h"
#include "logger.h"
#include "plugin_factory.h"
#include "fetcher.h"
#include "radon.h"
#include <NFmiLocation.h>
#include <NFmiMetTime.h>

using namespace std;
using namespace himan;
using namespace himan::plugin;

// rampDown function returns a value between 1 and 0,
// depending where valueInBetween is in the interval between start and end.

double rampDown(const double& start, const double& end, const double& valueInBetween)
{
	if (valueInBetween <= start)
		return 1.0;

	if (valueInBetween >= end)
		return 0.0;

	return (end - valueInBetween) / (end - start);
}

const param FParam("PROB-FROST-1");

frost::frost()
{
	itsLogger = logger("frost");
}

void frost::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	SetParams({FParam});

	Start();
}

void frost::Calculate(shared_ptr<info<double>> myTargetInfo, unsigned short threadIndex)
{
	NFmiMetTime theTime(static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%Y"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%m"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%d"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%H"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%M"))));

	const param TParam("T-K");
	const param TDParam("TD-K");
	const param TGParam("TG-K");
	const param WGParam("FFG-MS");
	const param T0Param("PROB-TC-0");
	const param NParam("N-PRCNT");
	const param RADParam("RADGLO-WM2");
	const param ICNParam("IC-0TO1");
	//const param LCParam("LC-0TO1");

	auto myThreadedLogger = logger("frostThread #" + to_string(threadIndex));

	forecast_time forecastTime = myTargetInfo->Time();
	level forecastLevel = myTargetInfo->Level();
	forecast_type forecastType = myTargetInfo->ForecastType();

	myThreadedLogger.Info("Calculating time " + static_cast<string>(forecastTime.ValidDateTime()) + ", level " +
			static_cast<string>(forecastLevel));

	// Get the latest data from producer 181.

	info_t TInfo = Fetch(forecastTime, level(kHeight, 2), TParam, forecastType, false);
	info_t TDInfo = Fetch(forecastTime, level(kHeight, 2), TDParam, forecastType, false);
	info_t NInfo = Fetch(forecastTime, level(kHeight, 0), NParam, forecastType, false);

	// Change forecastTime for producer 131 due to varying forecastTime with producer 181.

        auto r = GET_PLUGIN(radon);
        auto latestFromDatabase = r->RadonDB().GetLatestTime(131, "", 0);
        forecastTime.OriginDateTime(latestFromDatabase);

        info_t TGInfo = Fetch(forecastTime, level(kGroundDepth, 0, 7), TGParam, forecastType, false);
        info_t WGInfo = Fetch(forecastTime, level(kGround, 0), WGParam, forecastType, false);

	// Change forecastTime to 00 or 12 if necessary.

	int latestHour = std::stoi(forecastTime.OriginDateTime().String("%H"));

	if (latestHour > 0 && latestHour < 12)
	{
		 forecastTime.OriginDateTime().Adjust(kHourResolution, -latestHour);
	}
	if (latestHour > 12 && latestHour <= 23)
	{
		forecastTime.OriginDateTime().Adjust(kHourResolution, -latestHour);
		forecastTime.OriginDateTime().Adjust(kHourResolution, 12);
	}

	info_t ICNInfo = Fetch(forecastTime, level(kGround, 0), ICNParam, forecastType, false);

        //info_t LCInfo = Fetch(forecastTime, level(kGround, 0), LCParam, forecastType, false);

	// Get the latest RADGLO-WM2.

	info_t RADInfo;

        latestFromDatabase = r->RadonDB().GetLatestTime(240, "ECGLO0100", 0);
	forecastTime.OriginDateTime(latestFromDatabase);

	auto cnf = make_shared<plugin_configuration>(*itsConfiguration);
        auto f = GET_PLUGIN(fetcher);

        try
        {
                cnf->SourceProducers({producer(240, 86, 240, "ECGMTA")});
                RADInfo = f->Fetch(cnf, forecastTime, level(kHeight, 0), RADParam, forecastType, false);
        }
        catch (HPExceptionType& e)
        {
                if  (e == kFileDataNotFound)
                {
                        myThreadedLogger.Error("No data found.");
                }
                return;
        }

	// Get the latest ECMWF PROB-TC-0.

	info_t T0ECInfo;

	latestFromDatabase = r->RadonDB().GetLatestTime(242, "ECEUR0200", 0);
        forecastTime.OriginDateTime(latestFromDatabase);

	forecast_type stat_type = forecast_type(kStatisticalProcessing);

	try
	{
		cnf->SourceProducers({producer(242, 86, 242, "ECM_PROB")});
		cnf->SourceGeomNames({"ECEUR0200"});
		T0ECInfo = f->Fetch(cnf, forecastTime, level(kGround, 0), T0Param, stat_type, false);
	}
	catch (HPExceptionType& e)
	{
		if  (e == kFileDataNotFound)
		{
			myThreadedLogger.Error("No data found.");
		}
		return;
	}

	// Get the latest MEPS PROB-TC-0 from hour 00, 03, 06, 09, 12, 15, 18 or 21.

	info_t T0MEPSInfo;

	latestFromDatabase = r->RadonDB().GetLatestTime(260, "MEPS2500D", 1);
	forecastTime.OriginDateTime(latestFromDatabase);
	latestHour = std::stoi(forecastTime.OriginDateTime().String("%H"));

        if (latestHour == 1 || latestHour == 4 || latestHour == 7 || latestHour == 10 ||latestHour == 13
		|| latestHour == 16 ||latestHour == 19 || latestHour == 22)
        {
                 forecastTime.OriginDateTime().Adjust(kHourResolution, -1);
        }

        if (latestHour == 2 || latestHour == 5 || latestHour == 8 || latestHour == 11 ||latestHour == 14
		|| latestHour == 17 ||latestHour == 20 || latestHour == 23)
        {
                forecastTime.OriginDateTime().Adjust(kHourResolution, -2);
        }

	try
	{
		cnf->SourceProducers({producer(260, 86, 204, "MEPSMTA")});
		cnf->SourceGeomNames({"MEPS2500D"});
		T0MEPSInfo = f->Fetch(cnf, forecastTime, level(kHeight, 2), T0Param, stat_type, false);
	}
	catch (HPExceptionType& e)
	{
                if  (e == kFileDataNotFound)
                {
                        myThreadedLogger.Error("No data found.");
                }
                return;
	}

	if (!TInfo || !TDInfo || !TGInfo || !WGInfo || !NInfo || !RADInfo || !T0ECInfo || !T0MEPSInfo || !ICNInfo) // LCINfo removed.
	{
		myThreadedLogger.Warning("Skipping step " + static_cast<string>(forecastTime.Step()) + ", level " +
			static_cast<string>(forecastLevel));
		return;
	}

	string deviceType = "CPU";

	LOCKSTEP(myTargetInfo, TInfo, TDInfo, TGInfo, WGInfo, NInfo, RADInfo, T0ECInfo, T0MEPSInfo, ICNInfo) // LCInfo removed.

	{
		double T = TInfo->Value() - himan::constants::kKelvin;
		double TD = TDInfo->Value() - himan::constants::kKelvin;
		double TG = TGInfo->Value() - himan::constants::kKelvin;
		double WG = WGInfo->Value();
		double N = NInfo->Value();
		double RAD = RADInfo->Value();
		double T0EC = T0ECInfo->Value();
		double T0MEPS = T0MEPSInfo->Value();
		double ICN = ICNInfo->Value();
		//double LC = LCInfo->Value();

		if (IsMissingValue({T, TD, TG, WG, N, RAD, T0EC, T0MEPS, ICN})) // LC
		{
			continue;
		}

		// Calculating indexes and coefficients.

		// dewIndex

		double dewIndex = kHPMissingValue;

		dewIndex = rampDown(-5.0, 5.0, TD); // TD -5...5

		// nIndex

		double nIndex = kHPMissingValue;

		nIndex = (100.0 - N) / 100.0;

		// tIndexHigh

		double tIndexHigh = kHPMissingValue;

		tIndexHigh = rampDown(2.5, 15.0, T) * rampDown(2.5, 15.0, T);

		// wgWind

		double wgWind = kHPMissingValue;

		wgWind = rampDown(1.0, 6.0, WG);

		double lowWindCoef = 1.0;
		double nCoef = 1.0;
		double weight = 4.0;
		double stabCoef = 1.5 * wgWind + 1.0;

		// Adjusting coefficients when T above and near zero.

		if (T >= 0 && T < 2.5)
		{
			lowWindCoef = rampDown(0, 2.5, T) * weight + 1.0;
			nCoef = 1.0 / lowWindCoef;
		}

		// Calculating frost probability.

		double frost_prob = MissingDouble();

		if (T < -3.0)
		{
			frost_prob = 1.0;
		}

		else if (T < 0)
		{
			frost_prob = 0.9;
		}

		else
		{
			frost_prob = ((lowWindCoef * dewIndex) + stabCoef + (nCoef * nIndex)) /
				(lowWindCoef + stabCoef + (1.0 / lowWindCoef)) * tIndexHigh;
		}

		// Raising the frost probability due to ground temperature TG.

		double tgModel = kHPMissingValue;

		if (T < 5.0)
		{
			tgModel = sqrt(rampDown(-6.0, 5.0, TG));
		}

		if (frost_prob < tgModel)
		{
			frost_prob = tgModel;
		}

		// Raising the frost probability due to probability of T<0 and T. Both EC and MEPS cases.

		if (T0EC > 0.6 && T < 5.0 && frost_prob < T0EC)
		{
			frost_prob = T0EC;
		}

		if (frost_prob < T0MEPS && T0MEPS > 0.4)
		{
			frost_prob = (frost_prob * 2.0 + T0MEPS) / 3.0;
		}

		// No frost when radiation is high enough. Valid in  1.4.-15.9.

		int month = stoi(forecastTime.ValidDateTime().String("%m"));
		int day = stoi(forecastTime.ValidDateTime().String("%d"));

		if ((month >= 4 && month <= 8) || (month == 9 && day <= 15))
		{
			if (RAD > 175)
			{
				frost_prob = 0.0;
			}

		}

		// Lowering frost probability due to sun's elevation angle. Valid in 1.4.-15.9.

		if ((month >= 4 && month <= 8) || (month == 9 && day <= 15))
		{
			NFmiLocation theLocation(myTargetInfo->LatLon().X(), myTargetInfo->LatLon().Y());

                	double elevationAngle = theLocation.ElevationAngle(theTime);
                	double angleCoef = kHPMissingValue;

			angleCoef = rampDown(-1.0, 20.0, elevationAngle);

			frost_prob = angleCoef * frost_prob;
		}

		// No frost probability on sea when there is no ice.

		/*if (ICN == 0 &&  LC == 0)
		{
			frost_prob = 0;
		}*/

		// Lowering frost probability when forecasted T is high enough.

		if (T > 6.0)
		{
			frost_prob = frost_prob * rampDown(6.0, 15.0, T);
		}

		myTargetInfo->Value(frost_prob);

	}

	myThreadedLogger.Info("[" + deviceType + "] Missing values: " + to_string(myTargetInfo->Data().MissingCount()) +
	                      "/" + to_string(myTargetInfo->Data().Size()));
}
<commit_msg>Code review changes, checks for forecast availability etc.<commit_after>#include "frost.h"
#include "forecast_time.h"
#include "level.h"
#include "logger.h"
#include "plugin_factory.h"
#include "fetcher.h"
#include "radon.h"
#include <NFmiLocation.h>
#include <NFmiMetTime.h>

using namespace std;
using namespace himan;
using namespace himan::plugin;

// rampDown function returns a value between 1 and 0,
// depending where valueInBetween is in the interval between start and end.

double rampDown(const double& start, const double& end, const double& valueInBetween)
{
	if (valueInBetween <= start)
		return 1.0;

	if (valueInBetween >= end)
		return 0.0;

	return (end - valueInBetween) / (end - start);
}

const param FParam("PROB-FROST-1");

frost::frost()
{
	itsLogger = logger("frost");
}

void frost::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	SetParams({FParam});

	Start();
}

void frost::Calculate(shared_ptr<info<double>> myTargetInfo, unsigned short threadIndex)
{
	NFmiMetTime theTime(static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%Y"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%m"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%d"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%H"))),
	                    static_cast<short>(stoi(myTargetInfo->Time().ValidDateTime().String("%M"))));

	const param TParam("T-K");
	const param TDParam("TD-K");
	const param TGParam("TG-K");
	const param WGParam("FFG-MS");
	const param T0Param("PROB-TC-0");
	const param NParam("N-PRCNT");
	const param RADParam("RADGLO-WM2");
	const param ICNParam("IC-0TO1");
	const param LCParam("LC-0TO1");

	auto myThreadedLogger = logger("frostThread #" + to_string(threadIndex));

	forecast_time forecastTime = myTargetInfo->Time();
	level forecastLevel = myTargetInfo->Level();
	forecast_type forecastType = myTargetInfo->ForecastType();

	myThreadedLogger.Info("Calculating time " + static_cast<string>(forecastTime.ValidDateTime()) + ", level " +
			static_cast<string>(forecastLevel));

	// Get the latest data from producer 181.

	info_t TInfo = Fetch(forecastTime, level(kHeight, 2), TParam, forecastType, false);
	info_t TDInfo = Fetch(forecastTime, level(kHeight, 2), TDParam, forecastType, false);
	info_t NInfo = Fetch(forecastTime, level(kHeight, 0), NParam, forecastType, false);

	// Change forecastTime for producer 131 due to varying forecastTime with producer 181.

        auto r = GET_PLUGIN(radon);
        auto latestFromDatabase = r->RadonDB().GetLatestTime(131, "", 0);
        forecastTime.OriginDateTime(latestFromDatabase);

        auto cnf = make_shared<plugin_configuration>(*itsConfiguration);
        auto f = GET_PLUGIN(fetcher);

	// Get the latest TG-K.

	info_t TGInfo;

        try
        {
                cnf->SourceProducers({producer(131, 98, 150, "ECG")});
                TGInfo = f->Fetch(cnf, forecastTime, level(kGroundDepth, 0, 7), TGParam, forecastType, false);
        }
        catch (HPExceptionType& e)
        {
                if  (e == kFileDataNotFound)
                {
                        myThreadedLogger.Error("No data found.");
                }
                return;
        }

	// Get the latest FFG-MS.

	info_t WGInfo;

        try
        {
                cnf->SourceProducers({producer(131, 98, 150, "ECG")});
                WGInfo = f->Fetch(cnf, forecastTime, level(kGround, 0), WGParam, forecastType, false);
        }
        catch (HPExceptionType& e)
        {
                if  (e == kFileDataNotFound)
                {
                        myThreadedLogger.Error("No data found.");
                }
                return;
        }

	// Get the latest IC-0TO1.

	info_t ICNInfo;

	// Change forecastTime to 00 or 12 if necessary.

	int latestHour = std::stoi(forecastTime.OriginDateTime().String("%H"));

	if (latestHour > 0 && latestHour < 12)
	{
		 forecastTime.OriginDateTime().Adjust(kHourResolution, -latestHour);
	}
	if (latestHour > 12 && latestHour <= 23)
	{
		forecastTime.OriginDateTime().Adjust(kHourResolution, -latestHour);
		forecastTime.OriginDateTime().Adjust(kHourResolution, 12);
	}

        try
        {
                cnf->SourceProducers({producer(131, 98, 150, "ECG")});
                ICNInfo = f->Fetch(cnf, forecastTime, level(kGround, 0), ICNParam, forecastType, false);
        }
        catch (HPExceptionType& e)
        {
                if  (e == kFileDataNotFound)
                {
                        myThreadedLogger.Error("No data found.");
                }
                return;
        }

	// Get the latest LC-0TO1, avalable only for hour 00.

        info_t LCInfo;

	forecast_time LC_time(forecastTime.OriginDateTime(), forecastTime.ValidDateTime());
	latestFromDatabase = r->RadonDB().GetLatestTime(131, "ECEUR0100", 0);
        LC_time.OriginDateTime(latestFromDatabase);
	LC_time.ValidDateTime(forecastTime.OriginDateTime());

        try
        {
                cnf->SourceProducers({producer(131, 98, 150, "ECG")});
		cnf->SourceGeomNames({"ECEUR0100"});
                LCInfo = f->Fetch(cnf, LC_time, level(kGround, 0), LCParam, forecastType, false);
        }
        catch (HPExceptionType& e)
        {
                if  (e == kFileDataNotFound)
                {
                        myThreadedLogger.Error("No data found.");
                }
                return;
        }

	// Get the latest RADGLO-WM2.

	info_t RADInfo;

        latestFromDatabase = r->RadonDB().GetLatestTime(240, "ECGLO0100", 0);
	forecastTime.OriginDateTime(latestFromDatabase);

        try
        {
                cnf->SourceProducers({producer(240, 86, 240, "ECGMTA")});
		cnf->SourceGeomNames({"ECGLO0100"});
                RADInfo = f->Fetch(cnf, forecastTime, level(kHeight, 0), RADParam, forecastType, false);
        }
        catch (HPExceptionType& e)
        {
                if  (e == kFileDataNotFound)
                {
                        myThreadedLogger.Error("No data found.");
                }
                return;
        }

	// Get the latest ECMWF PROB-TC-0. If not found, get earlier.

	info_t T0ECInfo;

	forecast_type stat_type = forecast_type(kStatisticalProcessing);

	int ec_offset = 0;

	latestFromDatabase = r->RadonDB().GetLatestTime(242, "ECEUR0200", ec_offset);
        forecastTime.OriginDateTime(latestFromDatabase);

	// ECMWF PROB-TC-0 is calculated only for every 3 hours.

	int forecastHour = std::stoi(forecastTime.ValidDateTime().String("%H"));

        if (forecastHour % 3 == 1 || forecastHour % 3 == 2)
        {
                myThreadedLogger.Error("ECMWF PROB-TC-0 not available for forecast hour: " + forecastTime.ValidDateTime().String("%H"));
                return;
        }

        bool success = false;

	while (success == false)
	{

		latestHour = std::stoi(forecastTime.OriginDateTime().String("%H"));

		try
		{
			success = true;
			cnf->SourceProducers({producer(242, 86, 242, "ECM_PROB")});
			cnf->SourceGeomNames({"ECEUR0200"});
			T0ECInfo = f->Fetch(cnf, forecastTime, level(kGround, 0), T0Param, stat_type, false);
		}
		catch (HPExceptionType& e)
		{
			if  (e == kFileDataNotFound)
			{
				myThreadedLogger.Error("No data found.");
			}
			ec_offset++;

			if  (ec_offset > 1)
			{
				return;
			}
			latestFromDatabase = r->RadonDB().GetLatestTime(242, "ECEUR0200", ec_offset);
			const string analtime = forecastTime.OriginDateTime().String("%Y-%m-%d %H:%M:%S");
			myThreadedLogger.Error("ECMWF PROB-TC-0 from analysis time " + analtime + " not found, using " +
				static_cast<string>(latestFromDatabase));
			forecastTime.OriginDateTime(latestFromDatabase);
			success = false;
		}
	}

	// Get the latest MEPS PROB-TC-0 from hour 00, 03, 06, 09, 12, 15, 18 or 21. If not found get earlier.

	info_t T0MEPSInfo;

	int MEPS_offset = 1;
	success = false;

	latestFromDatabase = r->RadonDB().GetLatestTime(260, "MEPS2500D", MEPS_offset);
	forecastTime.OriginDateTime(latestFromDatabase);

        while (success == false)
        {
		latestHour = std::stoi(forecastTime.OriginDateTime().String("%H"));

        	if (latestHour == 1 || latestHour == 4 || latestHour == 7 || latestHour == 10 ||latestHour == 13
			|| latestHour == 16 ||latestHour == 19 || latestHour == 22)
        	{
                 	forecastTime.OriginDateTime().Adjust(kHourResolution, -1);
        	}

        	if (latestHour == 2 || latestHour == 5 || latestHour == 8 || latestHour == 11 ||latestHour == 14
			|| latestHour == 17 ||latestHour == 20 || latestHour == 23)
        	{
                	forecastTime.OriginDateTime().Adjust(kHourResolution, -2);
        	}

		try
		{
			success = true;
			cnf->SourceProducers({producer(260, 86, 204, "MEPSMTA")});
			cnf->SourceGeomNames({"MEPS2500D"});
			T0MEPSInfo = f->Fetch(cnf, forecastTime, level(kHeight, 2), T0Param, stat_type, false);
		}
		catch (HPExceptionType& e)
		{
                	if  (e == kFileDataNotFound)
                	{
                        	myThreadedLogger.Error("No data found.");

			}
			MEPS_offset++;

			if (MEPS_offset > 2)
			{
				return;
			}
			latestFromDatabase = r->RadonDB().GetLatestTime(260, "MEPS2500D", MEPS_offset);
			const string analtime = forecastTime.OriginDateTime().String("%Y-%m-%d %H:%M:%S");
			myThreadedLogger.Error("MEPS PROB-TC-0 from analysis time " + analtime +
				" not found, using " + static_cast<string>(latestFromDatabase));
			forecastTime.OriginDateTime(latestFromDatabase);
			success = false;
		}
	}

	if (!TInfo || !TDInfo || !TGInfo || !WGInfo || !NInfo || !RADInfo || !T0ECInfo || !T0MEPSInfo || !ICNInfo || !LCInfo)
	{
		myThreadedLogger.Warning("Skipping step " + static_cast<string>(forecastTime.Step()) + ", level " +
			static_cast<string>(forecastLevel));
		return;
	}

	string deviceType = "CPU";

	LOCKSTEP(myTargetInfo, TInfo, TDInfo, TGInfo, WGInfo, NInfo, RADInfo, T0ECInfo, T0MEPSInfo, ICNInfo, LCInfo)

	{
		double T = TInfo->Value() - himan::constants::kKelvin;
		double TD = TDInfo->Value() - himan::constants::kKelvin;
		double TG = TGInfo->Value() - himan::constants::kKelvin;
		double WG = WGInfo->Value();
		double N = NInfo->Value();
		double RAD = RADInfo->Value();
		double T0EC = T0ECInfo->Value();
		double T0MEPS = T0MEPSInfo->Value();
		double ICN = ICNInfo->Value();
		double LC = LCInfo->Value();

		if (IsMissingValue({T, TD, TG, WG, N, RAD, T0EC, T0MEPS, ICN, LC}))
		{
			continue;
		}

		// Calculating indexes and coefficients.

		// dewIndex

		double dewIndex = kHPMissingValue;

		dewIndex = rampDown(-5.0, 5.0, TD); // TD -5...5

		// nIndex

		double nIndex = kHPMissingValue;

		nIndex = (100.0 - N) / 100.0;

		// tIndexHigh

		double tIndexHigh = kHPMissingValue;

		tIndexHigh = rampDown(2.5, 15.0, T) * rampDown(2.5, 15.0, T);

		// wgWind

		double wgWind = kHPMissingValue;

		wgWind = rampDown(1.0, 6.0, WG);

		double lowWindCoef = 1.0;
		double nCoef = 1.0;
		double weight = 4.0;
		double stabCoef = 1.5 * wgWind + 1.0;

		// Adjusting coefficients when T above and near zero.

		if (T >= 0 && T < 2.5)
		{
			lowWindCoef = rampDown(0, 2.5, T) * weight + 1.0;
			nCoef = 1.0 / lowWindCoef;
		}

		// Calculating frost probability.

		double frost_prob = MissingDouble();

		if (T < -3.0)
		{
			frost_prob = 1.0;
		}

		else if (T < 0)
		{
			frost_prob = 0.9;
		}

		else
		{
			frost_prob = ((lowWindCoef * dewIndex) + stabCoef + (nCoef * nIndex)) /
				(lowWindCoef + stabCoef + (1.0 / lowWindCoef)) * tIndexHigh;
		}

		// Raising the frost probability due to ground temperature TG.

		double tgModel = kHPMissingValue;

		if (T < 5.0)
		{
			tgModel = sqrt(rampDown(-6.0, 5.0, TG));
		}

		if (frost_prob < tgModel)
		{
			frost_prob = tgModel;
		}

		// Raising the frost probability due to probability of T<0 and T. Both EC and MEPS cases.

		if (T0EC > 0.6 && T < 5.0 && frost_prob < T0EC)
		{
			frost_prob = T0EC;
		}

		if (frost_prob < T0MEPS && T0MEPS > 0.4)
		{
			frost_prob = (frost_prob * 2.0 + T0MEPS) / 3.0;
		}

		// No frost when radiation is high enough. Valid in  1.4.-15.9.

		int month = stoi(forecastTime.ValidDateTime().String("%m"));
		int day = stoi(forecastTime.ValidDateTime().String("%d"));

		if ((month >= 4 && month <= 8) || (month == 9 && day <= 15))
		{
			if (RAD > 175)
			{
				frost_prob = 0.0;
			}

		}

		// Lowering frost probability due to sun's elevation angle. Valid in 1.4.-15.9.

		if ((month >= 4 && month <= 8) || (month == 9 && day <= 15))
		{
			NFmiLocation theLocation(myTargetInfo->LatLon().X(), myTargetInfo->LatLon().Y());

                	double elevationAngle = theLocation.ElevationAngle(theTime);
                	double angleCoef = kHPMissingValue;

			angleCoef = rampDown(-1.0, 20.0, elevationAngle);

			frost_prob = angleCoef * frost_prob;
		}

		// No frost probability on sea when there is no ice.

		if (ICN == 0 &&  LC == 0)
		{
			frost_prob = 0;
		}

		// Lowering frost probability when forecasted T is high enough.

		if (T > 6.0)
		{
			frost_prob = frost_prob * rampDown(6.0, 15.0, T);
		}

		myTargetInfo->Value(frost_prob);

	}

	myThreadedLogger.Info("[" + deviceType + "] Missing values: " + to_string(myTargetInfo->Data().MissingCount()) +
	                      "/" + to_string(myTargetInfo->Data().Size()));
}
<|endoftext|>


<commit_before>/* options.cpp - CS 472 Project #2: Genetic Programming
 * Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for options namespace
 */

#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>

#include "options.hpp"

namespace options
{
  Position::Position(): x{0}, y{0}, direction{Direction::east} {}

  Map::Map(): width{0}, height{0}, ticks{0}, max_ticks{0}, score{0}, pieces{0},
	      position{Position{}} {}

  Map::Map(std::string filename, unsigned int ticks):
    width{0}, height{0}, ticks{0}, max_ticks{ticks}, score{0}, pieces{0},
    position{Position{}}
  {
    // Try to open the given file.
    std::ifstream data_file{filename};
    if (not data_file.is_open())
      {
	std::cerr << "File " << filename << " could not be read!\n";
	std::exit(EXIT_FAILURE);
      }

    // Parse file into map structure
    std::string line;
    while (data_file >> line)
      {
	std::vector<Cell> row;
	if (width != 0) row.reserve(width);
	for (const char& c : line)
	  {
	    if (c != '.' and c != 'x' and c != '\n')
	      {
		std::cerr << "File " << filename << " had bad cells!\n"
			  << "They were: " << c << std::endl;
		std::exit(EXIT_FAILURE);
	      }
	    else if (c != '\n')
	      {
		Cell cell = (c == 'x') ? Cell{Cell::food} : Cell{Cell::blank};
		row.emplace_back(cell);
		if (cell == Cell::food) ++pieces;
	      }
	  }
	if (width == 0) width = row.size(); // Get initial width
	else if (row.size() != width)
	  {
	    // Verify all lines are same width
	    std::cerr << "File " << filename << " had uneven lines!\n"
		      << "The width is: " << width
		      << " and the line was " << row.size() << std::endl;
	    std::exit(EXIT_FAILURE);
	  }
	rows.emplace_back(row);
      }
    height = rows.size();
  }

  bool
  Map::active() const
    {
      return ticks < max_ticks;
    }

  bool
  Map::look() const
    {
      Position ahead = position;
      if (position.direction == Direction::north)
	ahead.y = (position.y - 1) % height;
      else if (position.direction == Direction::west)
	ahead.x = (position.x - 1) % width;
      else if (position.direction == Direction::south)
	ahead.y = (position.y + 1) % height;
      else if (position.direction == Direction::east)
	ahead.y = (position.x + 1) % width;

      return rows[ahead.y][ahead.x] == Cell::food;
    }

  bool
  Map::forward()
    {
      // Move forward in specified direction
      if (position.direction == Direction::north)
	position.y = (position.y - 1) % height;
      else if (position.direction == Direction::west)
	position.x = (position.x - 1) % width;
      else if (position.direction == Direction::south)
	position.y = (position.y + 1) % height;
      else if (position.direction == Direction::east)
	position.y = (position.x + 1) % width;

      // Increment score if moved onto food
      if (rows[position.y][position.x] == Cell::food) ++score;

      // Mark location on map as visitied
      rows[position.y][position.x] = Cell::marked;

      ++ticks;
      return active();
    }

  bool
  Map::left()
    {
      if (position.direction == Direction::north)
	position.direction = Direction::west;
      else if (position.direction == Direction::west)
	position.direction = Direction::south;
      else if (position.direction == Direction::south)
	position.direction = Direction::east;
      else if (position.direction == Direction::east)
	position.direction = Direction::north;

      ++ticks;
      return active();
    }

  bool
  Map::right()
    {
      if (position.direction == Direction::north)
	position.direction = Direction::east;
      else if (position.direction == Direction::east)
	position.direction = Direction::south;
      else if (position.direction == Direction::south)
	position.direction = Direction::west;
      else if (position.direction == Direction::west)
	position.direction = Direction::north;

      ++ticks;
      return active();
    }

  unsigned int
  Map::fitness() const
    {
      return score;
    }

  unsigned int
  Map::max() const
    {
      return pieces;
    }

  std::string Map::print() const
    {
      std::stringstream out;
      out << "# 'x' is food and 'o' is ant trail\n";
      for (const std::vector<Cell>& row : rows)
	{
	  for (const Cell& cell : row)
	    {
	      // Add blank, food, and marked locations
	      if (cell == Cell::blank) out << '.';
	      else if (cell == Cell::food) out << 'x';
	      else if (cell == Cell::marked) out << 'o';
	      else
		{
		  std::cerr << "Map is malformed!\n";
		  std::exit(EXIT_FAILURE);
		}
	    }
	  // Add newline after each row
	  out << '\n';
	}
      return out.str();
    }

  // Validates options parameters; should instead be unit tests.
  void
  Options::validate() const
  {
    assert(trials > 0);
    assert(iterations > 0);
    assert(population_size > 0);
    assert(tournament_size > 0 and tournament_size <= population_size);
    assert(crossover_size == 2);
    assert(elitism_size <= population_size);
    assert(grow_chance >= 0 and grow_chance <= 1);
    assert(mutate_chance >= 0 and mutate_chance <= 1);
    assert(crossover_chance >= 0 and crossover_chance <= 1);
    assert(internals_chance >= 0 and internals_chance <= 1);
  }

  /* Given main's argc and argv, this will parse command-line options
     and the optional config file to return a built-up Options struct
     with all values, default or explicitly set. */
  const Options
  parse(int argc, char* argv[])
  {
    using std::string;
    using namespace boost::program_options;

    string filename;
    unsigned int ticks;
    Options options;

    positional_options_description positionals;
    variables_map variables_map;
    options_description description{"Allowed options"};

    // sets up all available CLI options
    description.add_options()
      ("help,h", "produce help message")

      ("config,c", value<string>()->
       default_value("search.cfg"),
       "specify the configuration file")

      ("file,f", value<string>(&filename)->
       default_value("test/santa-fe-trail.dat"),
       "specify the location of the columnized test data \"X Y\"")

      ("trials,t", value<unsigned int>(&options.trials)->
       default_value(4),
       "set the number of trials to run")

      ("iterations,i",
       value<unsigned int>(&options.iterations)->
       default_value(128),
       "set the number of iterations for which to run each trial")

      ("population,p",
       value<unsigned int>(&options.population_size)->
       default_value(128),
       "set the size of each population")

      ("depth,d", value<unsigned int>(&options.max_depth)->
       default_value(4),
       "set the maximum depth for initial populations")

      ("tournament,T",
       value<unsigned int>(&options.tournament_size)->
       default_value(3),
       "set the tournment size to adjust selection pressure")

      ("crossover,C",
       value<unsigned int>(&options.crossover_size)->
       default_value(2),
       "set the crossover size(binary in current implementation)")

      ("elitism,e", value<unsigned int>(&options.elitism_size)->
       default_value(2),
       "set the number of elitism replacements to make each iteration")

      ("ticks", value<unsigned int>(&ticks)->
       default_value(600),
       "set the number of moves the any may move")

      ("penalty,P", value<double>(&options.penalty)->
       default_value(0.1),
       "set the constant scalar of the size penalty for fitness")

      ("grow,g", value<double>(&options.grow_chance)->
       default_value(0.5),
       "set the probability that an initial tree will be made by the grow method")

      ("mutate,m", value<double>(&options.mutate_chance)->
       default_value(0.01),
       "set the probability that a single node will mutate")

      ("crossover_chance", value<double>(&options.crossover_chance)->
       default_value(0.8),
       "set the probability that a selected pair of invididuals will undergo crossover")

      ("internals,I", value<double>(&options.internals_chance)->
       default_value(0.9),
       "set the probability that a crossover target node will be an internal node")

      ("logs", value<string>(&options.logs_dir)->
       default_value("logs/"),
       "set the save directory for log files")

      ("plots", value<string>(&options.plots_dir)->
       default_value("plots/"),
       "set the save directory for plot data files")

      ("verbosity,v", value<unsigned int>(&options.verbosity)->
       default_value(1),
       "set the verbosity: 0 - no logging; 1 - normal logging; 2 - debug output");

    /* Stores CLI and config file options. Will catch exception and
       exit with EXIT_FAILURE if given bad input. */
    try
      {
	store(parse_command_line(argc, argv, description), variables_map);

	std::ifstream config{variables_map["config"].as<string>()};
	if (config.is_open())
	  store(parse_config_file(config, description), variables_map);

	notify(variables_map);
      }
    catch (std::exception& e)
      {
	std::cerr << e.what() << std::endl;
	std::exit(EXIT_FAILURE);
      }

    // Print options help and exit with EXIT_SUCCESS when finished.
    if (variables_map.count("help"))
      {
	std::cout << "Genetic Program implemented in C++ by Andrew Schwartzmeyer\n"
		  << "Code located at https://github.com/andschwa/uidaho-cs472-project2\n\n"
		  << "Logs saved to <logs>/<Unix time>.dat\n"
		  << "Plot data saved to <plots>/<Unix time>.dat\n"
		  << "GNUPlot PNG generation script './plot <plots>'\n\n"
		  << description << std::endl;
	std::exit(EXIT_SUCCESS);
      }

    // get values from given test file
    options.map = Map(filename, ticks);
    options.validate();

    return options;
  }
}
<commit_msg>Alex wins; switched to switches; reindented<commit_after>/* options.cpp - CS 472 Project #2: Genetic Programming
 * Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for options namespace
 */

#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>

#include "options.hpp"

namespace options
{
  Position::Position(): x{0}, y{0}, direction{Direction::east} {}

  Map::Map(): width{0}, height{0}, ticks{0}, max_ticks{0}, score{0}, pieces{0},
	      position{Position{}} {}

  Map::Map(std::string filename, unsigned int ticks):
    width{0}, height{0}, ticks{0}, max_ticks{ticks}, score{0}, pieces{0},
    position{Position{}}
  {
    // Try to open the given file.
    std::ifstream data_file{filename};
    if (not data_file.is_open())
      {
	std::cerr << "File " << filename << " could not be read!\n";
	std::exit(EXIT_FAILURE);
      }

    // Parse file into map structure
    std::string line;
    while (data_file >> line)
      {
	std::vector<Cell> row;
	if (width != 0) row.reserve(width);
	for (const char& c : line)
	  {
	    if (c != '.' and c != 'x' and c != '\n')
	      {
		std::cerr << "File " << filename << " had bad cells!\n"
			  << "They were: " << c << std::endl;
		std::exit(EXIT_FAILURE);
	      }
	    else if (c != '\n')
	      {
		Cell cell = (c == 'x') ? Cell{Cell::food} : Cell{Cell::blank};
		row.emplace_back(cell);
		if (cell == Cell::food) ++pieces;
	      }
	  }
	if (width == 0) width = row.size(); // Get initial width
	else if (row.size() != width)
	  {
	    // Verify all lines are same width
	    std::cerr << "File " << filename << " had uneven lines!\n"
		      << "The width is: " << width
		      << " and the line was " << row.size() << std::endl;
	    std::exit(EXIT_FAILURE);
	  }
	rows.emplace_back(row);
      }
    height = rows.size();
  }

  bool
  Map::active() const
  {
    return ticks < max_ticks;
  }

  bool
  Map::look() const
  {
    Position ahead = position;
    switch (position.direction)
      {
      case Direction::north:
	ahead.y = (position.y - 1) % height;
	break;
      case Direction::west:
	ahead.x = (position.x - 1) % width;
	break;
      case Direction::south:
	ahead.y = (position.y + 1) % height;
	break;
      case Direction::east:
	ahead.y = (position.x + 1) % width;
	break;
      }
    return rows[ahead.y][ahead.x] == Cell::food;
  }

  bool
  Map::forward()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.y = (position.y - 1) % height;
	break;
      case Direction::west:
	position.x = (position.x - 1) % width;
	break;
      case Direction::south:
	position.y = (position.y + 1) % height;
	break;
      case Direction::east:
	position.y = (position.x + 1) % width;
	break;
      }
    // Increment score if moved onto food
    if (rows[position.y][position.x] == Cell::food) ++score;

    // Mark location on map as visitied
    rows[position.y][position.x] = Cell::marked;

    ++ticks;
    return active();
  }

  bool
  Map::left()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.direction = Direction::west;
	break;
      case Direction::west:
	position.direction = Direction::south;
	break;
      case Direction::south:
	position.direction = Direction::east;
	break;
      case Direction::east:
	position.direction = Direction::north;
	break;
      }
    ++ticks;
    return active();
  }

  bool
  Map::right()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.direction = Direction::east;
	break;
      case Direction::east:
	position.direction = Direction::south;
	break;
      case Direction::south:
	position.direction = Direction::west;
	break;
      case Direction::west:
	position.direction = Direction::north;
	break;
      }
    ++ticks;
    return active();
  }

  unsigned int
  Map::fitness() const
  {
    return score;
  }

  unsigned int
  Map::max() const
  {
    return pieces;
  }

  std::string Map::print() const
  {
    std::stringstream out;
    out << "# 'x' is food and 'o' is ant trail\n";
    for (const std::vector<Cell>& row : rows)
      {
	for (const Cell& cell : row)
	  {
	    // Add blank, food, and marked locations
	    if (cell == Cell::blank) out << '.';
	    else if (cell == Cell::food) out << 'x';
	    else if (cell == Cell::marked) out << 'o';
	    else
	      {
		std::cerr << "Map is malformed!\n";
		std::exit(EXIT_FAILURE);
	      }
	  }
	// Add newline after each row
	out << '\n';
      }
    return out.str();
  }

  // Validates options parameters; should instead be unit tests.
  void
  Options::validate() const
  {
    assert(trials > 0);
    assert(iterations > 0);
    assert(population_size > 0);
    assert(tournament_size > 0 and tournament_size <= population_size);
    assert(crossover_size == 2);
    assert(elitism_size <= population_size);
    assert(grow_chance >= 0 and grow_chance <= 1);
    assert(mutate_chance >= 0 and mutate_chance <= 1);
    assert(crossover_chance >= 0 and crossover_chance <= 1);
    assert(internals_chance >= 0 and internals_chance <= 1);
  }

  /* Given main's argc and argv, this will parse command-line options
     and the optional config file to return a built-up Options struct
     with all values, default or explicitly set. */
  const Options
  parse(int argc, char* argv[])
  {
    using std::string;
    using namespace boost::program_options;

    string filename;
    unsigned int ticks;
    Options options;

    positional_options_description positionals;
    variables_map variables_map;
    options_description description{"Allowed options"};

    // sets up all available CLI options
    description.add_options()
      ("help,h", "produce help message")

      ("config,c", value<string>()->
       default_value("search.cfg"),
       "specify the configuration file")

      ("file,f", value<string>(&filename)->
       default_value("test/santa-fe-trail.dat"),
       "specify the location of the columnized test data \"X Y\"")

      ("trials,t", value<unsigned int>(&options.trials)->
       default_value(4),
       "set the number of trials to run")

      ("iterations,i",
       value<unsigned int>(&options.iterations)->
       default_value(128),
       "set the number of iterations for which to run each trial")

      ("population,p",
       value<unsigned int>(&options.population_size)->
       default_value(128),
       "set the size of each population")

      ("depth,d", value<unsigned int>(&options.max_depth)->
       default_value(4),
       "set the maximum depth for initial populations")

      ("tournament,T",
       value<unsigned int>(&options.tournament_size)->
       default_value(3),
       "set the tournment size to adjust selection pressure")

      ("crossover,C",
       value<unsigned int>(&options.crossover_size)->
       default_value(2),
       "set the crossover size(binary in current implementation)")

      ("elitism,e", value<unsigned int>(&options.elitism_size)->
       default_value(2),
       "set the number of elitism replacements to make each iteration")

      ("ticks", value<unsigned int>(&ticks)->
       default_value(600),
       "set the number of moves the any may move")

      ("penalty,P", value<double>(&options.penalty)->
       default_value(0.1),
       "set the constant scalar of the size penalty for fitness")

      ("grow,g", value<double>(&options.grow_chance)->
       default_value(0.5),
       "set the probability that an initial tree will be made by the grow method")

      ("mutate,m", value<double>(&options.mutate_chance)->
       default_value(0.01),
       "set the probability that a single node will mutate")

      ("crossover_chance", value<double>(&options.crossover_chance)->
       default_value(0.8),
       "set the probability that a selected pair of invididuals will undergo crossover")

      ("internals,I", value<double>(&options.internals_chance)->
       default_value(0.9),
       "set the probability that a crossover target node will be an internal node")

      ("logs", value<string>(&options.logs_dir)->
       default_value("logs/"),
       "set the save directory for log files")

      ("plots", value<string>(&options.plots_dir)->
       default_value("plots/"),
       "set the save directory for plot data files")

      ("verbosity,v", value<unsigned int>(&options.verbosity)->
       default_value(1),
       "set the verbosity: 0 - no logging; 1 - normal logging; 2 - debug output");

    /* Stores CLI and config file options. Will catch exception and
       exit with EXIT_FAILURE if given bad input. */
    try
      {
	store(parse_command_line(argc, argv, description), variables_map);

	std::ifstream config{variables_map["config"].as<string>()};
	if (config.is_open())
	  store(parse_config_file(config, description), variables_map);

	notify(variables_map);
      }
    catch (std::exception& e)
      {
	std::cerr << e.what() << std::endl;
	std::exit(EXIT_FAILURE);
      }

    // Print options help and exit with EXIT_SUCCESS when finished.
    if (variables_map.count("help"))
      {
	std::cout << "Genetic Program implemented in C++ by Andrew Schwartzmeyer\n"
		  << "Code located at https://github.com/andschwa/uidaho-cs472-project2\n\n"
		  << "Logs saved to <logs>/<Unix time>.dat\n"
		  << "Plot data saved to <plots>/<Unix time>.dat\n"
		  << "GNUPlot PNG generation script './plot <plots>'\n\n"
		  << description << std::endl;
	std::exit(EXIT_SUCCESS);
      }

    // get values from given test file
    options.map = Map(filename, ticks);
    options.validate();

    return options;
  }
}
<|endoftext|>


<commit_before>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef _TRAFFICMANAGER_HPP_
#define _TRAFFICMANAGER_HPP_

#include <list>
#include <map>
#include <set>

#include "module.hpp"
#include "config_utils.hpp"
#include "network.hpp"
#include "flit.hpp"
#include "buffer_state.hpp"
#include "stats.hpp"
#include "traffic.hpp"
#include "routefunc.hpp"
#include "outputset.hpp"
#include "injection.hpp"
#include <assert.h>

//register the requests to a node
struct Packet_Reply {
  int source;
  int time;
  int ttime;
  bool record;
  Flit::FlitType type;
};

class TrafficManager : public Module {
protected:
  unsigned int _sources;
  unsigned int _dests;
  unsigned int _routers;

  vector<Network *> _net;
  vector<vector<Router *> > _router_map;

  // ============ Message priorities ============

  enum ePriority { class_based, age_based, network_age_based, local_age_based, queue_length_based, hop_count_based, sequence_based, none };

  ePriority _pri_type;
  int       _classes;

  // ============ Injection VC states  ============

  vector<vector<BufferState *> > _buf_states;

  // ============ Injection queues ============

  int          _voqing;
  vector<vector<int> > _qtime;
  vector<vector<bool> > _qdrained;
  vector<vector<vector<list<Flit *> > > > _partial_packets;

  map<int, Flit *> _measured_in_flight_flits;
  multimap<int, Flit *> _measured_in_flight_packets;
  map<int, Flit *> _total_in_flight_flits;
  multimap<int, Flit *> _total_in_flight_packets;
  bool                _empty_network;
  bool _use_lagging;

  // ============ sub-networks and deadlock ==========

  short _duplicate_networks;
  unsigned char _deadlock_counter;

  // ============ batch mode ==========================
  vector<int> _packets_sent;
  int _batch_size;
  int _batch_count;
  vector<list<int> > _repliesPending;
  map<int, Packet_Reply*> _repliesDetails;
  vector<int> _requestsOutstanding;
  int _maxOutstanding;
  bool _replies_inherit_priority;

  int _last_id;
  int _last_pid;

  // ============voq mode =============================
  vector<vector<list<Flit*> > > _voq;
  vector<list<int> > _active_list;
  vector<vector<bool> > _active_vc;

  // ============ Statistics ============

  vector<Stats *> _latency_stats;
  vector<Stats *> _overall_min_latency;
  vector<Stats *> _overall_avg_latency;
  vector<Stats *> _overall_max_latency;

  vector<Stats *> _tlat_stats;
  vector<Stats *> _overall_min_tlat;
  vector<Stats *> _overall_avg_tlat;
  vector<Stats *> _overall_max_tlat;

  vector<Stats *> _frag_stats;
  vector<Stats *> _overall_min_frag;
  vector<Stats *> _overall_avg_frag;
  vector<Stats *> _overall_max_frag;

  vector<Stats *> _pair_latency;
  vector<Stats *> _pair_tlat;
  Stats * _hop_stats;

  vector<Stats *> _sent_flits;
  vector<Stats *> _accepted_flits;
  Stats * _overall_accepted;
  Stats * _overall_accepted_min;

  Stats * _batch_time;
  Stats * _overall_batch_time;

  vector<unsigned int> _injected_flow;
  vector<unsigned int> _ejected_flow;
  vector<unsigned int> _received_flow;
  vector<unsigned int> _sent_flow;

  vector<int> _slowest_flit;

  map<string, Stats *> _stats;

  // ============ Simulation parameters ============

  enum eSimState { warming_up, running, draining, done };
  eSimState _sim_state;

  enum eSimMode { latency, throughput, batch };
  eSimMode _sim_mode;

  //batched time-mode, know what you are doing
  bool _timed_mode;

  int   _limit; //any higher clients do not generate packets

  int   _warmup_time;
  int   _drain_time;

  float _load;
  float _flit_rate;

  int   _packet_size;

  /*false means all packet types are the same length "gConstantsize"
   *All packets uses all VCS
   *packet types are generated randomly, essentially making it only 1 type
   *of packet in the network
   *
   *True means only request packets are generated and replies are generated
   *as a response to the requests, packets are now difference length, correspond
   *to "read_request_size" etc.
   */
  bool _use_read_write;

  int _read_request_size;
  int _read_reply_size;
  int _write_request_size;
  int _write_reply_size;

  int   _total_sims;
  int   _sample_period;
  int   _max_samples;
  int   _warmup_periods;
  vector<vector<short> > _class_array;
  short _sub_network;

  int   _include_queuing;

  double _latency_thres;
  double _stopping_threshold;
  double _acc_stopping_threshold;
  double _warmup_threshold;

  float _internal_speedup;
  vector<float> _partial_internal_cycles;

  int _cur_id;
  int _cur_pid;
  int _time;

  list<Flit *> _used_flits;
  list<Flit *> _free_flits;

  tTrafficFunction  _traffic_function;
  tRoutingFunction  _routing_function;
  tInjectionProcess _injection_process;

  set<int> _flits_to_watch;
  set<int> _packets_to_watch;

  bool _print_csv_results;
  bool _print_vc_stats;
  string _traffic;
  bool _drain_measured_only;

  //flits to watch
  ostream * _stats_out;
  ostream * _flow_out;

  // ============ Internal methods ============
protected:
  virtual Flit *_NewFlit( );
  virtual void _RetireFlit( Flit *f, int dest );

  void _FirstStep( );
  void _NormalInject();
  void _BatchInject();
  void _Step( );

  bool _PacketsOutstanding( ) const;

  virtual int  _IssuePacket( int source, int cl );
  virtual void _GeneratePacket( int source, int size, int cl, int time );

  void _ClearStats( );

  int  _ComputeStats( const vector<Stats *> & stats, double *avg, double *min ) const;

  virtual bool _SingleSim( );

  int DivisionAlgorithm(int packet_type);

  void _DisplayRemaining( ) const;

  void _LoadWatchList(const string & filename);

public:
  TrafficManager( const Configuration &config, const vector<Network *> & net );
  ~TrafficManager( );

  bool Run( );

  void DisplayStats();

  const Stats * GetOverallLatency(int c) { return _overall_avg_latency[c]; }
  const Stats * GetAccepted() { return _overall_accepted; }
  const Stats * GetAcceptedMin() { return _overall_accepted_min; }
  const Stats * GetHops() { return _hop_stats; }

  inline int getTime() { return _time;}
  Stats * getStats(const string & name) { return _stats[name]; }

};

#endif
<commit_msg>remove obsolete member variables<commit_after>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef _TRAFFICMANAGER_HPP_
#define _TRAFFICMANAGER_HPP_

#include <list>
#include <map>
#include <set>

#include "module.hpp"
#include "config_utils.hpp"
#include "network.hpp"
#include "flit.hpp"
#include "buffer_state.hpp"
#include "stats.hpp"
#include "traffic.hpp"
#include "routefunc.hpp"
#include "outputset.hpp"
#include "injection.hpp"
#include <assert.h>

//register the requests to a node
struct Packet_Reply {
  int source;
  int time;
  int ttime;
  bool record;
  Flit::FlitType type;
};

class TrafficManager : public Module {
protected:
  unsigned int _sources;
  unsigned int _dests;
  unsigned int _routers;

  vector<Network *> _net;
  vector<vector<Router *> > _router_map;

  // ============ Message priorities ============

  enum ePriority { class_based, age_based, network_age_based, local_age_based, queue_length_based, hop_count_based, sequence_based, none };

  ePriority _pri_type;
  int       _classes;

  // ============ Injection VC states  ============

  vector<vector<BufferState *> > _buf_states;

  // ============ Injection queues ============

  int          _voqing;
  vector<vector<int> > _qtime;
  vector<vector<bool> > _qdrained;
  vector<vector<vector<list<Flit *> > > > _partial_packets;

  map<int, Flit *> _measured_in_flight_flits;
  multimap<int, Flit *> _measured_in_flight_packets;
  map<int, Flit *> _total_in_flight_flits;
  multimap<int, Flit *> _total_in_flight_packets;
  bool                _empty_network;
  bool _use_lagging;

  // ============ sub-networks and deadlock ==========

  short _duplicate_networks;
  unsigned char _deadlock_counter;

  // ============ batch mode ==========================
  vector<int> _packets_sent;
  int _batch_size;
  int _batch_count;
  vector<list<int> > _repliesPending;
  map<int, Packet_Reply*> _repliesDetails;
  vector<int> _requestsOutstanding;
  int _maxOutstanding;
  bool _replies_inherit_priority;

  int _last_id;
  int _last_pid;

  // ============voq mode =============================
  vector<vector<list<Flit*> > > _voq;
  vector<list<int> > _active_list;
  vector<vector<bool> > _active_vc;

  // ============ Statistics ============

  vector<Stats *> _latency_stats;
  vector<Stats *> _overall_min_latency;
  vector<Stats *> _overall_avg_latency;
  vector<Stats *> _overall_max_latency;

  vector<Stats *> _tlat_stats;
  vector<Stats *> _overall_min_tlat;
  vector<Stats *> _overall_avg_tlat;
  vector<Stats *> _overall_max_tlat;

  vector<Stats *> _frag_stats;
  vector<Stats *> _overall_min_frag;
  vector<Stats *> _overall_avg_frag;
  vector<Stats *> _overall_max_frag;

  vector<Stats *> _pair_latency;
  vector<Stats *> _pair_tlat;
  Stats * _hop_stats;

  vector<Stats *> _sent_flits;
  vector<Stats *> _accepted_flits;
  Stats * _overall_accepted;
  Stats * _overall_accepted_min;

  Stats * _batch_time;
  Stats * _overall_batch_time;

  vector<unsigned int> _injected_flow;
  vector<unsigned int> _ejected_flow;
  vector<unsigned int> _received_flow;
  vector<unsigned int> _sent_flow;

  vector<int> _slowest_flit;

  map<string, Stats *> _stats;

  // ============ Simulation parameters ============

  enum eSimState { warming_up, running, draining, done };
  eSimState _sim_state;

  enum eSimMode { latency, throughput, batch };
  eSimMode _sim_mode;

  //batched time-mode, know what you are doing
  bool _timed_mode;

  int   _limit; //any higher clients do not generate packets

  int   _warmup_time;
  int   _drain_time;

  float _load;
  float _flit_rate;

  int   _packet_size;

  /*false means all packet types are the same length "gConstantsize"
   *All packets uses all VCS
   *packet types are generated randomly, essentially making it only 1 type
   *of packet in the network
   *
   *True means only request packets are generated and replies are generated
   *as a response to the requests, packets are now difference length, correspond
   *to "read_request_size" etc.
   */
  bool _use_read_write;

  int _read_request_size;
  int _read_reply_size;
  int _write_request_size;
  int _write_reply_size;

  int   _total_sims;
  int   _sample_period;
  int   _max_samples;
  int   _warmup_periods;
  vector<vector<short> > _class_array;
  short _sub_network;

  int   _include_queuing;

  double _latency_thres;
  double _stopping_threshold;
  double _acc_stopping_threshold;
  double _warmup_threshold;

  float _internal_speedup;
  vector<float> _partial_internal_cycles;

  int _cur_id;
  int _cur_pid;
  int _time;

  tTrafficFunction  _traffic_function;
  tRoutingFunction  _routing_function;
  tInjectionProcess _injection_process;

  set<int> _flits_to_watch;
  set<int> _packets_to_watch;

  bool _print_csv_results;
  bool _print_vc_stats;
  string _traffic;
  bool _drain_measured_only;

  //flits to watch
  ostream * _stats_out;
  ostream * _flow_out;

  // ============ Internal methods ============
protected:
  virtual Flit *_NewFlit( );
  virtual void _RetireFlit( Flit *f, int dest );

  void _FirstStep( );
  void _NormalInject();
  void _BatchInject();
  void _Step( );

  bool _PacketsOutstanding( ) const;

  virtual int  _IssuePacket( int source, int cl );
  virtual void _GeneratePacket( int source, int size, int cl, int time );

  void _ClearStats( );

  int  _ComputeStats( const vector<Stats *> & stats, double *avg, double *min ) const;

  virtual bool _SingleSim( );

  int DivisionAlgorithm(int packet_type);

  void _DisplayRemaining( ) const;

  void _LoadWatchList(const string & filename);

public:
  TrafficManager( const Configuration &config, const vector<Network *> & net );
  ~TrafficManager( );

  bool Run( );

  void DisplayStats();

  const Stats * GetOverallLatency(int c) { return _overall_avg_latency[c]; }
  const Stats * GetAccepted() { return _overall_accepted; }
  const Stats * GetAcceptedMin() { return _overall_accepted_min; }
  const Stats * GetHops() { return _hop_stats; }

  inline int getTime() { return _time;}
  Stats * getStats(const string & name) { return _stats[name]; }

};

#endif
<|endoftext|>


<commit_before>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * trans/mangling.hpp
 * - Name mangling support
 *
 *
 * $D = ! type
 * $A = Array
 * $S = *-ptr
 * $R = &-ptr
 * $P = + symbol
 * $E = = symbol
 * $C = , symbol
 * $H = # symbol
 * $pL/$pR = Left/right paren
 * $aL/$aR = Left/right angle (<>)
 */
#include "mangling.hpp"
#include <hir/type.hpp>
#include <hir/path.hpp>

namespace {
    ::std::string   escape_str(const char* s, size_t len) {
        ::std::string   output;
        output.reserve(len + 1);
        for(auto vp = s; vp != s + len; vp ++)
        {
            auto v= *vp;
            if( v == '#' )
                output += "$H";
            else if( v == '-' )
                output += "_";
            else
                output += v;
        }
        return output;
    }
    ::std::string   escape_str(const RcString& s) {
        return escape_str(s.c_str(), s.size());
    }
    ::std::string   escape_str(const ::std::string& s) {
        return escape_str(s.c_str(), s.size());
    }
    ::FmtLambda emit_params(const ::HIR::PathParams& params)
    {
        return FMT_CB(ss,
            if( params.m_types.size() > 0 )
            {
                ss << "$aL";
                for(unsigned int i = 0; i < params.m_types.size(); i ++)
                {
                    if(i != 0)  ss << "$C";
                    ss << Trans_Mangle( params.m_types[i] );
                }
                ss << "$aR";
            }
            );
    }
}

::FmtLambda Trans_Mangle(const ::HIR::SimplePath& path)
{
    return FMT_CB(ss,
        ss << "_ZN";
        {
            ::std::string   cn;
            for(auto c : path.m_crate_name)
            {
                if(c == '-') {
                    cn += "$$";
                }
                else if(  ('0' <= c && c <= '9')
                       || ('A' <= c && c <= 'Z')
                       || ('a' <= c && c <= 'z')
                       || c == '_'
                       )
                {
                    cn += c;
                }
                else {
                }
            }
            ss << cn.size() << cn;
        }
        for(const auto& comp : path.m_components) {
            auto v = escape_str(comp);
            ss << v.size() << v;
        }
        );
}
::FmtLambda Trans_Mangle(const ::HIR::GenericPath& path)
{
    return FMT_CB(ss,
        ss << Trans_Mangle(path.m_path);
        ss << emit_params(path.m_params);
        );
}
::FmtLambda Trans_Mangle(const ::HIR::Path& path)
{
    TU_MATCHA( (path.m_data), (pe),
    (Generic,
        return Trans_Mangle(pe);
        ),
    (UfcsUnknown,
        BUG(Span(), "UfcsUnknown - " << path);
        ),
    (UfcsKnown,
        return FMT_CB(ss,
            ss << "_ZRK$aL";
            ss << Trans_Mangle(*pe.type);
            ss << "_as_";
            ss << Trans_Mangle(pe.trait);
            ss << "$aR";
            auto v = escape_str(pe.item);
            ss << v.size() << v;
            ss << emit_params(pe.params);
            );
        ),
    (UfcsInherent,
        return FMT_CB(ss,
            ss << "_ZRI$aL";
            ss << Trans_Mangle(*pe.type);
            ss << "$aR";
            auto v = escape_str(pe.item);
            ss << v.size() << v;
            ss << emit_params(pe.params);
            );
        )
    )
    throw "";
}
::FmtLambda Trans_Mangle(const ::HIR::TypeRef& ty)
{
    TU_MATCHA( (ty.m_data), (te),
    (Infer,
        BUG(Span(), "Infer in trans");
        ),
    (Diverge,
        return FMT_CB(ss, ss << "$D";);
        ),
    (Primitive,
        return FMT_CB(ss, ss << te;);
        ),
    (Path,
        return Trans_Mangle(te.path);
        ),
    (Generic,
        BUG(Span(), "Generic in trans - " << ty);
        ),
    (TraitObject,
        return FMT_CB(ss,
            ss << "$pL";
            ss << Trans_Mangle(te.m_trait.m_path);
            for(const auto& bound : te.m_trait.m_type_bounds) {
                ss << "_" << bound.first << "$E" << Trans_Mangle(bound.second);
            }
            for(const auto& marker : te.m_markers) {
                ss << "$P" << Trans_Mangle(marker);
            }
            ss << "$pR";
            );
        ),
    (ErasedType,
        BUG(Span(), "ErasedType in trans - " << ty);
        ),
    (Array,
        return FMT_CB(ss, ss << "$A" << te.size_val << "_" << Trans_Mangle(*te.inner););
        ),
    (Slice,
        return FMT_CB(ss, ss << "$A" << "_" << Trans_Mangle(*te.inner););
        ),
    (Tuple,
        return FMT_CB(ss,
            ss << "$T" << te.size();
            for(const auto& t : te)
                ss << "_" << Trans_Mangle(t);
            );
        ),
    (Borrow,
        return FMT_CB(ss,
            ss << "$R";
            switch(te.type)
            {
            case ::HIR::BorrowType::Shared: ss << "s"; break;
            case ::HIR::BorrowType::Unique: ss << "u"; break;
            case ::HIR::BorrowType::Owned : ss << "o"; break;
            }
            ss << "_" << Trans_Mangle(*te.inner);
            );
        ),
    (Pointer,
        return FMT_CB(ss,
            ss << "$S";
            switch(te.type)
            {
            case ::HIR::BorrowType::Shared: ss << "s"; break;
            case ::HIR::BorrowType::Unique: ss << "u"; break;
            case ::HIR::BorrowType::Owned : ss << "o"; break;
            }
            ss << "_" << Trans_Mangle(*te.inner);
            );
        ),
    (Function,
        return FMT_CB(ss,
            if(te.m_abi != "Rust")
                ss << "extern_" << escape_str(te.m_abi) << "_";
            if(te.is_unsafe)
                ss << "unsafe_";
            ss << "fn_" << te.m_arg_types.size();
            for(const auto& ty : te.m_arg_types)
                ss << "_" << Trans_Mangle(ty);
            ss << "_" << Trans_Mangle(*te.m_rettype);
            );
        ),
    (Closure,
        BUG(Span(), "Closure during trans - " << ty);
        )
    )

    throw "";
}

<commit_msg>(minor) Fix comment typo<commit_after>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * trans/mangling.cpp
 * - Name mangling support
 *
 *
 * $D = ! type
 * $A = Array
 * $S = *-ptr
 * $R = &-ptr
 * $P = + symbol
 * $E = = symbol
 * $C = , symbol
 * $H = # symbol
 * $pL/$pR = Left/right paren
 * $aL/$aR = Left/right angle (<>)
 */
#include "mangling.hpp"
#include <hir/type.hpp>
#include <hir/path.hpp>

namespace {
    ::std::string   escape_str(const char* s, size_t len) {
        ::std::string   output;
        output.reserve(len + 1);
        for(auto vp = s; vp != s + len; vp ++)
        {
            auto v= *vp;
            if( v == '#' )
                output += "$H";
            else if( v == '-' )
                output += "_";
            else
                output += v;
        }
        return output;
    }
    ::std::string   escape_str(const RcString& s) {
        return escape_str(s.c_str(), s.size());
    }
    ::std::string   escape_str(const ::std::string& s) {
        return escape_str(s.c_str(), s.size());
    }
    ::FmtLambda emit_params(const ::HIR::PathParams& params)
    {
        return FMT_CB(ss,
            if( params.m_types.size() > 0 )
            {
                ss << "$aL";
                for(unsigned int i = 0; i < params.m_types.size(); i ++)
                {
                    if(i != 0)  ss << "$C";
                    ss << Trans_Mangle( params.m_types[i] );
                }
                ss << "$aR";
            }
            );
    }
}

::FmtLambda Trans_Mangle(const ::HIR::SimplePath& path)
{
    return FMT_CB(ss,
        ss << "_ZN";
        {
            ::std::string   cn;
            for(auto c : path.m_crate_name)
            {
                if(c == '-') {
                    cn += "$$";
                }
                else if(  ('0' <= c && c <= '9')
                       || ('A' <= c && c <= 'Z')
                       || ('a' <= c && c <= 'z')
                       || c == '_'
                       )
                {
                    cn += c;
                }
                else {
                }
            }
            ss << cn.size() << cn;
        }
        for(const auto& comp : path.m_components) {
            auto v = escape_str(comp);
            ss << v.size() << v;
        }
        );
}
::FmtLambda Trans_Mangle(const ::HIR::GenericPath& path)
{
    return FMT_CB(ss,
        ss << Trans_Mangle(path.m_path);
        ss << emit_params(path.m_params);
        );
}
::FmtLambda Trans_Mangle(const ::HIR::Path& path)
{
    TU_MATCHA( (path.m_data), (pe),
    (Generic,
        return Trans_Mangle(pe);
        ),
    (UfcsUnknown,
        BUG(Span(), "UfcsUnknown - " << path);
        ),
    (UfcsKnown,
        return FMT_CB(ss,
            ss << "_ZRK$aL";
            ss << Trans_Mangle(*pe.type);
            ss << "_as_";
            ss << Trans_Mangle(pe.trait);
            ss << "$aR";
            auto v = escape_str(pe.item);
            ss << v.size() << v;
            ss << emit_params(pe.params);
            );
        ),
    (UfcsInherent,
        return FMT_CB(ss,
            ss << "_ZRI$aL";
            ss << Trans_Mangle(*pe.type);
            ss << "$aR";
            auto v = escape_str(pe.item);
            ss << v.size() << v;
            ss << emit_params(pe.params);
            );
        )
    )
    throw "";
}
::FmtLambda Trans_Mangle(const ::HIR::TypeRef& ty)
{
    TU_MATCHA( (ty.m_data), (te),
    (Infer,
        BUG(Span(), "Infer in trans");
        ),
    (Diverge,
        return FMT_CB(ss, ss << "$D";);
        ),
    (Primitive,
        return FMT_CB(ss, ss << te;);
        ),
    (Path,
        return Trans_Mangle(te.path);
        ),
    (Generic,
        BUG(Span(), "Generic in trans - " << ty);
        ),
    (TraitObject,
        return FMT_CB(ss,
            ss << "$pL";
            ss << Trans_Mangle(te.m_trait.m_path);
            for(const auto& bound : te.m_trait.m_type_bounds) {
                ss << "_" << bound.first << "$E" << Trans_Mangle(bound.second);
            }
            for(const auto& marker : te.m_markers) {
                ss << "$P" << Trans_Mangle(marker);
            }
            ss << "$pR";
            );
        ),
    (ErasedType,
        BUG(Span(), "ErasedType in trans - " << ty);
        ),
    (Array,
        return FMT_CB(ss, ss << "$A" << te.size_val << "_" << Trans_Mangle(*te.inner););
        ),
    (Slice,
        return FMT_CB(ss, ss << "$A" << "_" << Trans_Mangle(*te.inner););
        ),
    (Tuple,
        return FMT_CB(ss,
            ss << "$T" << te.size();
            for(const auto& t : te)
                ss << "_" << Trans_Mangle(t);
            );
        ),
    (Borrow,
        return FMT_CB(ss,
            ss << "$R";
            switch(te.type)
            {
            case ::HIR::BorrowType::Shared: ss << "s"; break;
            case ::HIR::BorrowType::Unique: ss << "u"; break;
            case ::HIR::BorrowType::Owned : ss << "o"; break;
            }
            ss << "_" << Trans_Mangle(*te.inner);
            );
        ),
    (Pointer,
        return FMT_CB(ss,
            ss << "$S";
            switch(te.type)
            {
            case ::HIR::BorrowType::Shared: ss << "s"; break;
            case ::HIR::BorrowType::Unique: ss << "u"; break;
            case ::HIR::BorrowType::Owned : ss << "o"; break;
            }
            ss << "_" << Trans_Mangle(*te.inner);
            );
        ),
    (Function,
        return FMT_CB(ss,
            if(te.m_abi != "Rust")
                ss << "extern_" << escape_str(te.m_abi) << "_";
            if(te.is_unsafe)
                ss << "unsafe_";
            ss << "fn_" << te.m_arg_types.size();
            for(const auto& ty : te.m_arg_types)
                ss << "_" << Trans_Mangle(ty);
            ss << "_" << Trans_Mangle(*te.m_rettype);
            );
        ),
    (Closure,
        BUG(Span(), "Closure during trans - " << ty);
        )
    )

    throw "";
}

<|endoftext|>