<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(ossrs)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <srs_app_log.hpp>

#include <stdarg.h>
#include <sys/time.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <srs_app_config.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_utility.hpp>
#include <srs_kernel_utility.hpp>

SrsThreadContext::SrsThreadContext()
{
}

SrsThreadContext::~SrsThreadContext()
{
}

int SrsThreadContext::generate_id()
{
    static int id = 100;

    int gid = id++;
    cache[st_thread_self()] = gid;
    return gid;
}

int SrsThreadContext::get_id()
{
    return cache[st_thread_self()];
}

int SrsThreadContext::set_id(int v)
{
    st_thread_t self = st_thread_self();

    int ov = 0;
    if (cache.find(self) != cache.end()) {
        ov = cache[self];
    }

    cache[self] = v;

    return ov;
}

void SrsThreadContext::clear_cid()
{
    st_thread_t self = st_thread_self();
    std::map<st_thread_t, int>::iterator it = cache.find(self);
    if (it != cache.end()) {
        cache.erase(it);
    }
}

// the max size of a line of log.
#define LOG_MAX_SIZE 4096

// the tail append to each log.
#define LOG_TAIL '\n'
// reserved for the end of log data, it must be strlen(LOG_TAIL)
#define LOG_TAIL_SIZE 1

SrsFastLog::SrsFastLog()
{
    _level = SrsLogLevel::Trace;
    log_data = new char[LOG_MAX_SIZE];

    fd = -1;
    log_to_file_tank = false;
    utc = false;
}

SrsFastLog::~SrsFastLog()
{
    srs_freepa(log_data);

    if (fd > 0) {
        ::close(fd);
        fd = -1;
    }

    if (_srs_config) {
        _srs_config->unsubscribe(this);
    }
}

int SrsFastLog::initialize()
{
    int ret = ERROR_SUCCESS;

    if (_srs_config) {
        _srs_config->subscribe(this);

        log_to_file_tank = _srs_config->get_log_tank_file();
        _level = srs_get_log_level(_srs_config->get_log_level());
        utc = _srs_config->get_utc_time();
    }

    return ret;
}

void SrsFastLog::verbose(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Verbose) {
        return;
    }

    int size = 0;
    if (!generate_header(false, tag, context_id, "verb", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Verbose);
}

void SrsFastLog::info(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Info) {
        return;
    }

    int size = 0;
    if (!generate_header(false, tag, context_id, "debug", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Info);
}

void SrsFastLog::trace(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Trace) {
        return;
    }

    int size = 0;
    if (!generate_header(false, tag, context_id, "trace", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Trace);
}

void SrsFastLog::warn(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Warn) {
        return;
    }

    int size = 0;
    if (!generate_header(true, tag, context_id, "warn", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Warn);
}

void SrsFastLog::error(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Error) {
        return;
    }

    int size = 0;
    if (!generate_header(true, tag, context_id, "error", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    // add strerror() to error msg.
    if (errno != 0) {
        size += snprintf(log_data + size, LOG_MAX_SIZE - size, "(%s)", strerror(errno));
    }

    write_log(fd, log_data, size, SrsLogLevel::Error);
}

int SrsFastLog::on_reload_utc_time()
{
    utc = _srs_config->get_utc_time();

    return ERROR_SUCCESS;
}

int SrsFastLog::on_reload_log_tank()
{
    int ret = ERROR_SUCCESS;

    if (!_srs_config) {
        return ret;
    }

    bool tank = log_to_file_tank;
    log_to_file_tank = _srs_config->get_log_tank_file();

    if (tank) {
        return ret;
    }

    if (!log_to_file_tank) {
        return ret;
    }

    if (fd > 0) {
        ::close(fd);
    }
    open_log_file();

    return ret;
}

int SrsFastLog::on_reload_log_level()
{
    int ret = ERROR_SUCCESS;

    if (!_srs_config) {
        return ret;
    }

    _level = srs_get_log_level(_srs_config->get_log_level());

    return ret;
}

int SrsFastLog::on_reload_log_file()
{
    int ret = ERROR_SUCCESS;

    if (!_srs_config) {
        return ret;
    }

    if (!log_to_file_tank) {
        return ret;
    }

    if (fd > 0) {
        ::close(fd);
    }
    open_log_file();

    return ret;
}

bool SrsFastLog::generate_header(bool error, const char* tag, int context_id, const char* level_name, int* header_size)
{
    // clock time
    timeval tv;
    if (gettimeofday(&tv, NULL) == -1) {
        return false;
    }

    // to calendar time
    struct tm* tm;
    if (utc) {
        if ((tm = gmtime(&tv.tv_sec)) == NULL) {
            return false;
        }
    } else {
        if ((tm = localtime(&tv.tv_sec)) == NULL) {
            return false;
        }
    }

    // write log header
    int log_header_size = -1;

    if (error) {
        if (tag) {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%s][%d][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, tag, getpid(), context_id, errno);
        } else {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%d][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, getpid(), context_id, errno);
        }
    } else {
        if (tag) {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%s][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, tag, getpid(), context_id);
        } else {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, getpid(), context_id);
        }
    }

    if (log_header_size == -1) {
        return false;
    }

    // write the header size.
    *header_size = srs_min(LOG_MAX_SIZE - 1, log_header_size);

    return true;
}

void SrsFastLog::write_log(int& fd, char *str_log, int size, int level)
{
    // ensure the tail and EOF of string
    //      LOG_TAIL_SIZE for the TAIL char.
    //      1 for the last char(0).
    size = srs_min(LOG_MAX_SIZE - 1 - LOG_TAIL_SIZE, size);

    // add some to the end of char.
    str_log[size++] = LOG_TAIL;

    // if not to file, to console and return.
    if (!log_to_file_tank) {
        // if is error msg, then print color msg.
        // \033[31m : red text code in shell
        // \033[32m : green text code in shell
        // \033[33m : yellow text code in shell
        // \033[0m : normal text code
        if (level <= SrsLogLevel::Trace) {
            printf("%.*s", size, str_log);
        } else if (level == SrsLogLevel::Warn) {
            printf("\033[33m%.*s\033[0m", size, str_log);
        } else{
            printf("\033[31m%.*s\033[0m", size, str_log);
        }
        fflush(stdout);

        return;
    }

    // open log file. if specified
    if (fd < 0) {
        open_log_file();
    }

    // write log to file.
    if (fd > 0) {
        ::write(fd, str_log, size);
    }
}

void SrsFastLog::open_log_file()
{
    if (!_srs_config) {
        return;
    }

    std::string filename = _srs_config->get_log_file();

    if (filename.empty()) {
        return;
    }

    fd = ::open(filename.c_str(), O_RDWR | O_APPEND);

    if(fd == -1 && errno == ENOENT) {
        fd = open(filename.c_str(),
            O_RDWR | O_CREAT | O_TRUNC,
            S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
        );
    }
}

<commit_msg>fix logrotate empty file hole issue (#1561)<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(ossrs)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <srs_app_log.hpp>

#include <stdarg.h>
#include <sys/time.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <srs_app_config.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_utility.hpp>
#include <srs_kernel_utility.hpp>

SrsThreadContext::SrsThreadContext()
{
}

SrsThreadContext::~SrsThreadContext()
{
}

int SrsThreadContext::generate_id()
{
    static int id = 100;

    int gid = id++;
    cache[st_thread_self()] = gid;
    return gid;
}

int SrsThreadContext::get_id()
{
    return cache[st_thread_self()];
}

int SrsThreadContext::set_id(int v)
{
    st_thread_t self = st_thread_self();

    int ov = 0;
    if (cache.find(self) != cache.end()) {
        ov = cache[self];
    }

    cache[self] = v;

    return ov;
}

void SrsThreadContext::clear_cid()
{
    st_thread_t self = st_thread_self();
    std::map<st_thread_t, int>::iterator it = cache.find(self);
    if (it != cache.end()) {
        cache.erase(it);
    }
}

// the max size of a line of log.
#define LOG_MAX_SIZE 4096

// the tail append to each log.
#define LOG_TAIL '\n'
// reserved for the end of log data, it must be strlen(LOG_TAIL)
#define LOG_TAIL_SIZE 1

SrsFastLog::SrsFastLog()
{
    _level = SrsLogLevel::Trace;
    log_data = new char[LOG_MAX_SIZE];

    fd = -1;
    log_to_file_tank = false;
    utc = false;
}

SrsFastLog::~SrsFastLog()
{
    srs_freepa(log_data);

    if (fd > 0) {
        ::close(fd);
        fd = -1;
    }

    if (_srs_config) {
        _srs_config->unsubscribe(this);
    }
}

int SrsFastLog::initialize()
{
    int ret = ERROR_SUCCESS;

    if (_srs_config) {
        _srs_config->subscribe(this);

        log_to_file_tank = _srs_config->get_log_tank_file();
        _level = srs_get_log_level(_srs_config->get_log_level());
        utc = _srs_config->get_utc_time();
    }

    return ret;
}

void SrsFastLog::verbose(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Verbose) {
        return;
    }

    int size = 0;
    if (!generate_header(false, tag, context_id, "verb", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Verbose);
}

void SrsFastLog::info(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Info) {
        return;
    }

    int size = 0;
    if (!generate_header(false, tag, context_id, "debug", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Info);
}

void SrsFastLog::trace(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Trace) {
        return;
    }

    int size = 0;
    if (!generate_header(false, tag, context_id, "trace", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Trace);
}

void SrsFastLog::warn(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Warn) {
        return;
    }

    int size = 0;
    if (!generate_header(true, tag, context_id, "warn", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    write_log(fd, log_data, size, SrsLogLevel::Warn);
}

void SrsFastLog::error(const char* tag, int context_id, const char* fmt, ...)
{
    if (_level > SrsLogLevel::Error) {
        return;
    }

    int size = 0;
    if (!generate_header(true, tag, context_id, "error", &size)) {
        return;
    }

    va_list ap;
    va_start(ap, fmt);
    // we reserved 1 bytes for the new line.
    size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
    va_end(ap);

    // add strerror() to error msg.
    if (errno != 0) {
        size += snprintf(log_data + size, LOG_MAX_SIZE - size, "(%s)", strerror(errno));
    }

    write_log(fd, log_data, size, SrsLogLevel::Error);
}

int SrsFastLog::on_reload_utc_time()
{
    utc = _srs_config->get_utc_time();

    return ERROR_SUCCESS;
}

int SrsFastLog::on_reload_log_tank()
{
    int ret = ERROR_SUCCESS;

    if (!_srs_config) {
        return ret;
    }

    bool tank = log_to_file_tank;
    log_to_file_tank = _srs_config->get_log_tank_file();

    if (tank) {
        return ret;
    }

    if (!log_to_file_tank) {
        return ret;
    }

    if (fd > 0) {
        ::close(fd);
    }
    open_log_file();

    return ret;
}

int SrsFastLog::on_reload_log_level()
{
    int ret = ERROR_SUCCESS;

    if (!_srs_config) {
        return ret;
    }

    _level = srs_get_log_level(_srs_config->get_log_level());

    return ret;
}

int SrsFastLog::on_reload_log_file()
{
    int ret = ERROR_SUCCESS;

    if (!_srs_config) {
        return ret;
    }

    if (!log_to_file_tank) {
        return ret;
    }

    if (fd > 0) {
        ::close(fd);
    }
    open_log_file();

    return ret;
}

bool SrsFastLog::generate_header(bool error, const char* tag, int context_id, const char* level_name, int* header_size)
{
    // clock time
    timeval tv;
    if (gettimeofday(&tv, NULL) == -1) {
        return false;
    }

    // to calendar time
    struct tm* tm;
    if (utc) {
        if ((tm = gmtime(&tv.tv_sec)) == NULL) {
            return false;
        }
    } else {
        if ((tm = localtime(&tv.tv_sec)) == NULL) {
            return false;
        }
    }

    // write log header
    int log_header_size = -1;

    if (error) {
        if (tag) {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%s][%d][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, tag, getpid(), context_id, errno);
        } else {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%d][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, getpid(), context_id, errno);
        }
    } else {
        if (tag) {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%s][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, tag, getpid(), context_id);
        } else {
            log_header_size = snprintf(log_data, LOG_MAX_SIZE,
                "[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%d][%d] ",
                1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000),
                level_name, getpid(), context_id);
        }
    }

    if (log_header_size == -1) {
        return false;
    }

    // write the header size.
    *header_size = srs_min(LOG_MAX_SIZE - 1, log_header_size);

    return true;
}

void SrsFastLog::write_log(int& fd, char *str_log, int size, int level)
{
    // ensure the tail and EOF of string
    //      LOG_TAIL_SIZE for the TAIL char.
    //      1 for the last char(0).
    size = srs_min(LOG_MAX_SIZE - 1 - LOG_TAIL_SIZE, size);

    // add some to the end of char.
    str_log[size++] = LOG_TAIL;

    // if not to file, to console and return.
    if (!log_to_file_tank) {
        // if is error msg, then print color msg.
        // \033[31m : red text code in shell
        // \033[32m : green text code in shell
        // \033[33m : yellow text code in shell
        // \033[0m : normal text code
        if (level <= SrsLogLevel::Trace) {
            printf("%.*s", size, str_log);
        } else if (level == SrsLogLevel::Warn) {
            printf("\033[33m%.*s\033[0m", size, str_log);
        } else{
            printf("\033[31m%.*s\033[0m", size, str_log);
        }
        fflush(stdout);

        return;
    }

    // open log file. if specified
    if (fd < 0) {
        open_log_file();
    }

    // write log to file.
    if (fd > 0) {
        ::write(fd, str_log, size);
    }
}

void SrsFastLog::open_log_file()
{
    if (!_srs_config) {
        return;
    }

    std::string filename = _srs_config->get_log_file();

    if (filename.empty()) {
        return;
    }

    fd = ::open(filename.c_str(), O_RDWR | O_APPEND);

    if(fd == -1 && errno == ENOENT) {
        fd = open(filename.c_str(),
            O_RDWR | O_CREAT | O_TRUNC | O_APPEND/*logrotate copytruncate need this flag*/,
            S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
        );
    }
}

<|endoftext|>


<commit_before>// Halide tutorial lesson 1.

// This lesson demonstrates basic usage of Halide as a JIT compiler for imaging.

// This lesson can be built by invoking the command:
//    make tutorial_lesson_01_basics
// in a shell with the current directory at the top of the halide source tree.
// Otherwise, see the platform-specific compiler invocations below.

// On linux, you can compile and run it like so:
// g++ lesson_01*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_01
// LD_LIBRARY_PATH=../bin ./lesson_01

// On os x:
// g++ lesson_01*.cpp -g -I ../include -L ../bin -lHalide -o lesson_01
// DYLD_LIBRARY_PATH=../bin ./lesson_01

// The only Halide header file you need is Halide.h. It includes all of Halide.
#include "Halide.h"

// We'll also include stdio for printf.
#include <stdio.h>

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

    // This program defines a single-stage imaging pipeline that
    // outputs a grayscale diagonal gradient.

    // A 'Func' object represents a pipeline stage. It's a pure
    // function that defines what value each pixel should have. You
    // can think of it as a computed image.
    Halide::Func gradient;

    // Var objects are names to use as variables in the definition of
    // a Func. They have no meaning by themselves.
    Halide::Var x, y;

    // We typically use Vars named 'x' and 'y' to correspond to the x
    // and y axes of an image, and we write them in that order. If
    // you're used to thinking of images as having rows and columns,
    // then x is the column index, and y is the row index.

    // Funcs are defined at any integer coordinate of its variables as
    // an Expr in terms of those variables and other functions.
    // Here, we'll define an Expr which has the value x + y. Vars have
    // appropriate operator overloading so that expressions like
    // 'x + y' become 'Expr' objects.
    Halide::Expr e = x + y;

    // Now we'll add a definition for the Func object. At pixel x, y,
    // the image will have the value of the Expr e. On the left hand
    // side we have the Func we're defining and some Vars. On the right
    // hand side we have some Expr object that uses those same Vars.
    gradient(x, y) = e;

    // This is the same as writing:
    //
    //   gradient(x, y) = x + y;
    //
    // which is the more common form, but we are showing the
    // intermediate Expr here for completeness.

    // That line of code defined the Func, but it didn't actually
    // compute the output image yet. At this stage it's just Funcs,
    // Exprs, and Vars in memory, representing the structure of our
    // imaging pipeline. We're meta-programming. This C++ program is
    // constructing a Halide program in memory. Actually computing
    // pixel data comes next.

    // Now we 'realize' the Func, which JIT compiles some code that
    // implements the pipeline we've defined, and then runs it.  We
    // also need to tell Halide the domain over which to evaluate the
    // Func, which determines the range of x and y above, and the
    // resolution of the output image. Halide.h also provides a basic
    // templatized Image type we can use. We'll make an 800 x 600
    // image.
    Halide::Image<int32_t> output = gradient.realize(800, 600);

    // Halide does type inference for you. Var objects represent
    // 32-bit integers, so the Expr object 'x + y' also represents a
    // 32-bit integer, and so 'gradient' defines a 32-bit image, and
    // so we got a 32-bit signed integer image out when we call
    // 'realize'. Halide types and type-casting rules are equivalent
    // to C.

    // Let's check everything worked, and we got the output we were
    // expecting:
    for (int j = 0; j < output.height(); j++) {
        for (int i = 0; i < output.width(); i++) {
            // We can access a pixel of an Image object using similar
            // syntax to defining and using functions.
            if (output(i, j) != i + j) {
                printf("Something went wrong!\n"
                       "Pixel %d, %d was supposed to be %d, but instead it's %d\n",
                       i, j, i+j, output(i, j));
                return -1;
            }
        }
    }

    // Everything worked! We defined a Func, then called 'realize' on
    // it to generate and run machine code that produced an Image.
    printf("Success!\n");

    return 0;
}
<commit_msg>Update lesson_01_basics.cpp<commit_after>// Halide tutorial lesson 1.

// This lesson demonstrates basic usage of Halide as a JIT compiler for imaging.

// This lesson can be built by invoking the command:
//    make tutorial_lesson_01_basics
// in a shell with the current directory at the top of the halide source tree.
// Otherwise, see the platform-specific compiler invocations below.

// On linux, you can compile and run it like so:
// g++ lesson_01*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_01 -std=c++1
// LD_LIBRARY_PATH=../bin ./lesson_01

// On os x:
// g++ lesson_01*.cpp -g -I ../include -L ../bin -lHalide -o lesson_01
// DYLD_LIBRARY_PATH=../bin ./lesson_01

// The only Halide header file you need is Halide.h. It includes all of Halide.
#include "Halide.h"

// We'll also include stdio for printf.
#include <stdio.h>

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

    // This program defines a single-stage imaging pipeline that
    // outputs a grayscale diagonal gradient.

    // A 'Func' object represents a pipeline stage. It's a pure
    // function that defines what value each pixel should have. You
    // can think of it as a computed image.
    Halide::Func gradient;

    // Var objects are names to use as variables in the definition of
    // a Func. They have no meaning by themselves.
    Halide::Var x, y;

    // We typically use Vars named 'x' and 'y' to correspond to the x
    // and y axes of an image, and we write them in that order. If
    // you're used to thinking of images as having rows and columns,
    // then x is the column index, and y is the row index.

    // Funcs are defined at any integer coordinate of its variables as
    // an Expr in terms of those variables and other functions.
    // Here, we'll define an Expr which has the value x + y. Vars have
    // appropriate operator overloading so that expressions like
    // 'x + y' become 'Expr' objects.
    Halide::Expr e = x + y;

    // Now we'll add a definition for the Func object. At pixel x, y,
    // the image will have the value of the Expr e. On the left hand
    // side we have the Func we're defining and some Vars. On the right
    // hand side we have some Expr object that uses those same Vars.
    gradient(x, y) = e;

    // This is the same as writing:
    //
    //   gradient(x, y) = x + y;
    //
    // which is the more common form, but we are showing the
    // intermediate Expr here for completeness.

    // That line of code defined the Func, but it didn't actually
    // compute the output image yet. At this stage it's just Funcs,
    // Exprs, and Vars in memory, representing the structure of our
    // imaging pipeline. We're meta-programming. This C++ program is
    // constructing a Halide program in memory. Actually computing
    // pixel data comes next.

    // Now we 'realize' the Func, which JIT compiles some code that
    // implements the pipeline we've defined, and then runs it.  We
    // also need to tell Halide the domain over which to evaluate the
    // Func, which determines the range of x and y above, and the
    // resolution of the output image. Halide.h also provides a basic
    // templatized Image type we can use. We'll make an 800 x 600
    // image.
    Halide::Image<int32_t> output = gradient.realize(800, 600);

    // Halide does type inference for you. Var objects represent
    // 32-bit integers, so the Expr object 'x + y' also represents a
    // 32-bit integer, and so 'gradient' defines a 32-bit image, and
    // so we got a 32-bit signed integer image out when we call
    // 'realize'. Halide types and type-casting rules are equivalent
    // to C.

    // Let's check everything worked, and we got the output we were
    // expecting:
    for (int j = 0; j < output.height(); j++) {
        for (int i = 0; i < output.width(); i++) {
            // We can access a pixel of an Image object using similar
            // syntax to defining and using functions.
            if (output(i, j) != i + j) {
                printf("Something went wrong!\n"
                       "Pixel %d, %d was supposed to be %d, but instead it's %d\n",
                       i, j, i+j, output(i, j));
                return -1;
            }
        }
    }

    // Everything worked! We defined a Func, then called 'realize' on
    // it to generate and run machine code that produced an Image.
    printf("Success!\n");

    return 0;
}
<|endoftext|>


<commit_before>// Halide tutorial lesson 13: Tuples

// This lesson describes how to write Funcs that evaluate to multiple
// values.

// On linux, you can compile and run it like so:
// g++ lesson_13*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_13 -std=c++11
// LD_LIBRARY_PATH=../bin ./lesson_13

// On os x:
// g++ lesson_13*.cpp -g -I ../include -L ../bin -lHalide -o lesson_13 -std=c++11
// DYLD_LIBRARY_PATH=../bin ./lesson_13

// If you have the entire Halide source tree, you can also build it by
// running:
//    make tutorial_lesson_13_tuples
// in a shell with the current directory at the top of the halide
// source tree.

#include "Halide.h"
#include <stdio.h>
#include <algorithm>
using namespace Halide;

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

    // So far Funcs (such as the one below) have evaluated to a single
    // scalar value for each point in their domain.
    Func single_valued;
    Var x, y;
    single_valued(x, y) = x + y;

    // One way to write a Func that returns a collection of values is
    // to add an additional dimension that indexes that
    // collection. This is how we typically deal with color. For
    // example, the Func below represents a collection of three values
    // for every x, y coordinate indexed by c.
    Func color_image;
    Var c;
    color_image(x, y, c) = select(c == 0, 245, // Red value
                                  c == 1, 42,  // Green value
                                  132);        // Blue value

    // This method is often convenient because it makes it easy to
    // operate on this Func in a way that treats each item in the
    // collection equally:
    Func brighter;
    brighter(x, y, c) = color_image(x, y, c) + 10;

    // However this method is also inconvenient for three reasons.
    //
    // 1) Funcs are defined over an infinite domain, so users of this
    // Func can for example access color_image(x, y, -17), which is
    // not a meaningful value and is probably indicative of a bug.
    //
    // 2) It requires a select, which can impact performance if not
    // bounded and unrolled:
    // brighter.bound(c, 0, 3).unroll(c);
    //
    // 3) With this method, all values in the collection must have the
    // same type. While the above two issues are merely inconvenient,
    // this one is a hard limitation that makes it impossible to
    // express certain things in this way.

    // It is also possible to represent a collection of values as a
    // collection of Funcs:
    Func func_array[3];
    func_array[0](x, y) = x + y;
    func_array[1](x, y) = sin(x);
    func_array[2](x, y) = cos(y);

    // This method avoids the three problems above, but introduces a
    // new annoyance. Because these are separate Funcs, it is
    // difficult to schedule them so that they are all computed
    // together inside a single loop over x, y.

    // A third alternative is to define a Func as evaluating to a
    // Tuple instead of an Expr. A Tuple is a fixed-size collection of
    // Exprs. Each Expr in a Tuple may have a different type. The
    // following function evaluates to an integer value (x+y), and a
    // floating point value (sin(x*y)).
    Func multi_valued;
    multi_valued(x, y) = Tuple(x + y, sin(x * y));

    // Realizing a tuple-valued Func returns a collection of
    // Buffers. We call this a Realization. It's equivalent to a
    // std::vector of Buffer objects:
    {
        Realization r = multi_valued.realize(80, 60);
        assert(r.size() == 2);
        Buffer<int> im0 = r[0];
        Buffer<float> im1 = r[1];
        assert(im0(30, 40) == 30 + 40);
        assert(im1(30, 40) == sinf(30 * 40));
    }

    // All Tuple elements are evaluated together over the same domain
    // in the same loop nest, but stored in distinct allocations. The
    // equivalent C++ code to the above is:
    {
        int multi_valued_0[80*60];
        float multi_valued_1[80*60];
        for (int y = 0; y < 80; y++) {
            for (int x = 0; x < 60; x++) {
                multi_valued_0[x + 60*y] = x + y;
                multi_valued_1[x + 60*y] = sinf(x*y);
            }
        }
    }

    // When compiling ahead-of-time, a Tuple-valued Func evaluates
    // into multiple distinct output buffer_t structs. These appear in
    // order at the end of the function signature:
    // int multi_valued(...input buffers and params...,
    //                  buffer_t *output_1, buffer_t *output_2);

    // You can construct a Tuple by passing multiple Exprs to the
    // Tuple constructor as we did above. Perhaps more elegantly, you
    // can also take advantage of C++11 initializer lists and just
    // enclose your Exprs in braces:
    Func multi_valued_2;
    multi_valued_2(x, y) = {x + y, sin(x*y)};

    // Calls to a multi-valued Func cannot be treated as Exprs. The
    // following is a syntax error:
    // Func consumer;
    // consumer(x, y) = multi_valued_2(x, y) + 10;

    // Instead you must index a Tuple with square brackets to retrieve
    // the individual Exprs:
    Expr integer_part = multi_valued_2(x, y)[0];
    Expr floating_part = multi_valued_2(x, y)[1];
    Func consumer;
    consumer(x, y) = {integer_part + 10, floating_part + 10.0f};

    // Tuple reductions.
    {
        // Tuples are particularly useful in reductions, as they allow
        // the reduction to maintain complex state as it walks along
        // its domain. The simplest example is an argmax.

        // First we create a Buffer to take the argmax over.
        Func input_func;
        input_func(x) = sin(x);
        Buffer<float> input = input_func.realize(100);

        // Then we define a 2-valued Tuple which tracks the index of
        // the maximum value and the value itself.
        Func arg_max;

        // Pure definition.
        arg_max() = {0, input(0)};

        // Update definition.
        RDom r(1, 99);
        Expr old_index = arg_max()[0];
        Expr old_max   = arg_max()[1];
        Expr new_index = select(old_max < input(r), r, old_index);
        Expr new_max   = max(input(r), old_max);
        arg_max() = {new_index, new_max};

        // The equivalent C++ is:
        int arg_max_0 = 0;
        float arg_max_1 = input(0);
        for (int r = 1; r < 100; r++) {
            int old_index = arg_max_0;
            float old_max = arg_max_1;
            int new_index = old_max < input(r) ? r : old_index;
            float new_max = std::max(input(r), old_max);
            // In a tuple update definition, all loads and computation
            // are done before any stores, so that all Tuple elements
            // are updated atomically with respect to recursive calls
            // to the same Func.
            arg_max_0 = new_index;
            arg_max_1 = new_max;
        }

        // Let's verify that the Halide and C++ found the same maximum
        // value and index.
        {
            Realization r = arg_max.realize();
            Buffer<int> r0 = r[0];
            Buffer<float> r1 = r[1];
            assert(arg_max_0 == r0(0));
            assert(arg_max_1 == r1(0));
        }

        // Halide provides argmax and argmin as built-in reductions
        // similar to sum, product, maximum, and minimum. They return
        // a Tuple consisting of the point in the reduction domain
        // corresponding to that value, and the value itself. In the
        // case of ties they return the first value found. We'll use
        // one of these in the following section.
    }

    // Tuples for user-defined types.
    {
        // Tuples can also be a convenient way to represent compound
        // objects such as complex numbers. Defining an object that
        // can be converted to and from a Tuple is one way to extend
        // Halide's type system with user-defined types.
        struct Complex {
            Expr real, imag;

            // Construct from a Tuple
            Complex(Tuple t) : real(t[0]), imag(t[1]) {}

            // Construct from a pair of Exprs
            Complex(Expr r, Expr i) : real(r), imag(i) {}

            // Construct from a call to a Func by treating it as a Tuple
            Complex(FuncRef t) : Complex(Tuple(t)) {}

            // Convert to a Tuple
            operator Tuple() const {
                return {real, imag};
            }

            // Complex addition
            Complex operator+(const Complex &other) const {
                return {real + other.real, imag + other.imag};
            }

            // Complex multiplication
            Complex operator*(const Complex &other) const {
                return {real * other.real - imag * other.imag,
                        real * other.imag + imag * other.real};
            }

            // Complex magnitude
            Expr magnitude() const {
                return real * real + imag * imag;
            }

            // Other complex operators would go here. The above are
            // sufficient for this example.
        };

        // Let's use the Complex struct to compute a Mandelbrot set.
        Func mandelbrot;

        // The initial complex value corresponding to an x, y coordinate
        // in our Func.
        Complex initial(x/15.0f - 2.5f, y/6.0f - 2.0f);

        // Pure definition.
        Var t;
        mandelbrot(x, y, t) = Complex(0.0f, 0.0f);

        // We'll use an update definition to take 12 steps.
        RDom r(1, 12);
        Complex current = mandelbrot(x, y, r-1);

        // The following line uses the complex multiplication and
        // addition we defined above.
        mandelbrot(x, y, r) = current*current + initial;

        // We'll use another tuple reduction to compute the iteration
        // number where the value first escapes a circle of radius 4.
        // This can be expressed as an argmin of a boolean - we want
        // the index of the first time the given boolean expression is
        // false (we consider false to be less than true).  The argmax
        // would return the index of the first time the expression is
        // true.

        Expr escape_condition = Complex(mandelbrot(x, y, r)).magnitude() < 16.0f;
        Tuple first_escape = argmin(escape_condition);

        // We only want the index, not the value, but argmin returns
        // both, so we'll index the argmin Tuple expression using
        // square brackets to get the Expr representing the index.
        Func escape;
        escape(x, y) = first_escape[0];

        // Realize the pipeline and print the result as ascii art.
        Buffer<int> result = escape.realize(61, 25);
        const char *code = " .:-~*={}&%#@";
        for (int y = 0; y < result.height(); y++) {
            for (int x = 0; x < result.width(); x++) {
                printf("%c", code[result(x, y)]);
            }
            printf("\n");
        }
    }

    printf("Success!\n");

    return 0;
}
<commit_msg>Fix https://github.com/halide/Halide/issues/2199 .<commit_after>// Halide tutorial lesson 13: Tuples

// This lesson describes how to write Funcs that evaluate to multiple
// values.

// On linux, you can compile and run it like so:
// g++ lesson_13*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_13 -std=c++11
// LD_LIBRARY_PATH=../bin ./lesson_13

// On os x:
// g++ lesson_13*.cpp -g -I ../include -L ../bin -lHalide -o lesson_13 -std=c++11
// DYLD_LIBRARY_PATH=../bin ./lesson_13

// If you have the entire Halide source tree, you can also build it by
// running:
//    make tutorial_lesson_13_tuples
// in a shell with the current directory at the top of the halide
// source tree.

#include "Halide.h"
#include <stdio.h>
#include <algorithm>
using namespace Halide;

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

    // So far Funcs (such as the one below) have evaluated to a single
    // scalar value for each point in their domain.
    Func single_valued;
    Var x, y;
    single_valued(x, y) = x + y;

    // One way to write a Func that returns a collection of values is
    // to add an additional dimension that indexes that
    // collection. This is how we typically deal with color. For
    // example, the Func below represents a collection of three values
    // for every x, y coordinate indexed by c.
    Func color_image;
    Var c;
    color_image(x, y, c) = select(c == 0, 245, // Red value
                                  c == 1, 42,  // Green value
                                  132);        // Blue value

    // This method is often convenient because it makes it easy to
    // operate on this Func in a way that treats each item in the
    // collection equally:
    Func brighter;
    brighter(x, y, c) = color_image(x, y, c) + 10;

    // However this method is also inconvenient for three reasons.
    //
    // 1) Funcs are defined over an infinite domain, so users of this
    // Func can for example access color_image(x, y, -17), which is
    // not a meaningful value and is probably indicative of a bug.
    //
    // 2) It requires a select, which can impact performance if not
    // bounded and unrolled:
    // brighter.bound(c, 0, 3).unroll(c);
    //
    // 3) With this method, all values in the collection must have the
    // same type. While the above two issues are merely inconvenient,
    // this one is a hard limitation that makes it impossible to
    // express certain things in this way.

    // It is also possible to represent a collection of values as a
    // collection of Funcs:
    Func func_array[3];
    func_array[0](x, y) = x + y;
    func_array[1](x, y) = sin(x);
    func_array[2](x, y) = cos(y);

    // This method avoids the three problems above, but introduces a
    // new annoyance. Because these are separate Funcs, it is
    // difficult to schedule them so that they are all computed
    // together inside a single loop over x, y.

    // A third alternative is to define a Func as evaluating to a
    // Tuple instead of an Expr. A Tuple is a fixed-size collection of
    // Exprs. Each Expr in a Tuple may have a different type. The
    // following function evaluates to an integer value (x+y), and a
    // floating point value (sin(x*y)).
    Func multi_valued;
    multi_valued(x, y) = Tuple(x + y, sin(x * y));

    // Realizing a tuple-valued Func returns a collection of
    // Buffers. We call this a Realization. It's equivalent to a
    // std::vector of Buffer objects:
    {
        Realization r = multi_valued.realize(80, 60);
        assert(r.size() == 2);
        Buffer<int> im0 = r[0];
        Buffer<float> im1 = r[1];
        assert(im0(30, 40) == 30 + 40);
        assert(im1(30, 40) == sinf(30 * 40));
    }

    // All Tuple elements are evaluated together over the same domain
    // in the same loop nest, but stored in distinct allocations. The
    // equivalent C++ code to the above is:
    {
        int multi_valued_0[80*60];
        float multi_valued_1[80*60];
        for (int y = 0; y < 80; y++) {
            for (int x = 0; x < 60; x++) {
                multi_valued_0[x + 60*y] = x + y;
                multi_valued_1[x + 60*y] = sinf(x*y);
            }
        }
    }

    // When compiling ahead-of-time, a Tuple-valued Func evaluates
    // into multiple distinct output buffer_t structs. These appear in
    // order at the end of the function signature:
    // int multi_valued(...input buffers and params...,
    //                  buffer_t *output_1, buffer_t *output_2);

    // You can construct a Tuple by passing multiple Exprs to the
    // Tuple constructor as we did above. Perhaps more elegantly, you
    // can also take advantage of C++11 initializer lists and just
    // enclose your Exprs in braces:
    Func multi_valued_2;
    multi_valued_2(x, y) = {x + y, sin(x*y)};

    // Calls to a multi-valued Func cannot be treated as Exprs. The
    // following is a syntax error:
    // Func consumer;
    // consumer(x, y) = multi_valued_2(x, y) + 10;

    // Instead you must index a Tuple with square brackets to retrieve
    // the individual Exprs:
    Expr integer_part = multi_valued_2(x, y)[0];
    Expr floating_part = multi_valued_2(x, y)[1];
    Func consumer;
    consumer(x, y) = {integer_part + 10, floating_part + 10.0f};

    // Tuple reductions.
    {
        // Tuples are particularly useful in reductions, as they allow
        // the reduction to maintain complex state as it walks along
        // its domain. The simplest example is an argmax.

        // First we create a Buffer to take the argmax over.
        Func input_func;
        input_func(x) = sin(x);
        Buffer<float> input = input_func.realize(100);

        // Then we define a 2-valued Tuple which tracks the index of
        // the maximum value and the value itself.
        Func arg_max;

        // Pure definition.
        arg_max() = {0, input(0)};

        // Update definition.
        RDom r(1, 99);
        Expr old_index = arg_max()[0];
        Expr old_max   = arg_max()[1];
        Expr new_index = select(old_max < input(r), r, old_index);
        Expr new_max   = max(input(r), old_max);
        arg_max() = {new_index, new_max};

        // The equivalent C++ is:
        int arg_max_0 = 0;
        float arg_max_1 = input(0);
        for (int r = 1; r < 100; r++) {
            int old_index = arg_max_0;
            float old_max = arg_max_1;
            int new_index = old_max < input(r) ? r : old_index;
            float new_max = std::max(input(r), old_max);
            // In a tuple update definition, all loads and computation
            // are done before any stores, so that all Tuple elements
            // are updated atomically with respect to recursive calls
            // to the same Func.
            arg_max_0 = new_index;
            arg_max_1 = new_max;
        }

        // Let's verify that the Halide and C++ found the same maximum
        // value and index.
        {
            Realization r = arg_max.realize();
            Buffer<int> r0 = r[0];
            Buffer<float> r1 = r[1];
            assert(arg_max_0 == r0(0));
            assert(arg_max_1 == r1(0));
        }

        // Halide provides argmax and argmin as built-in reductions
        // similar to sum, product, maximum, and minimum. They return
        // a Tuple consisting of the point in the reduction domain
        // corresponding to that value, and the value itself. In the
        // case of ties they return the first value found. We'll use
        // one of these in the following section.
    }

    // Tuples for user-defined types.
    {
        // Tuples can also be a convenient way to represent compound
        // objects such as complex numbers. Defining an object that
        // can be converted to and from a Tuple is one way to extend
        // Halide's type system with user-defined types.
        struct Complex {
            Expr real, imag;

            // Construct from a Tuple
            Complex(Tuple t) : real(t[0]), imag(t[1]) {}

            // Construct from a pair of Exprs
            Complex(Expr r, Expr i) : real(r), imag(i) {}

            // Construct from a call to a Func by treating it as a Tuple
            Complex(FuncRef t) : Complex(Tuple(t)) {}

            // Convert to a Tuple
            operator Tuple() const {
                return {real, imag};
            }

            // Complex addition
            Complex operator+(const Complex &other) const {
                return {real + other.real, imag + other.imag};
            }

            // Complex multiplication
            Complex operator*(const Complex &other) const {
                return {real * other.real - imag * other.imag,
                        real * other.imag + imag * other.real};
            }

            // Complex magnitude, squared for efficiency
            Expr magnitude_squared() const {
                return real * real + imag * imag;
            }

            // Other complex operators would go here. The above are
            // sufficient for this example.
        };

        // Let's use the Complex struct to compute a Mandelbrot set.
        Func mandelbrot;

        // The initial complex value corresponding to an x, y coordinate
        // in our Func.
        Complex initial(x/15.0f - 2.5f, y/6.0f - 2.0f);

        // Pure definition.
        Var t;
        mandelbrot(x, y, t) = Complex(0.0f, 0.0f);

        // We'll use an update definition to take 12 steps.
        RDom r(1, 12);
        Complex current = mandelbrot(x, y, r-1);

        // The following line uses the complex multiplication and
        // addition we defined above.
        mandelbrot(x, y, r) = current*current + initial;

        // We'll use another tuple reduction to compute the iteration
        // number where the value first escapes a circle of radius 4.
        // This can be expressed as an argmin of a boolean - we want
        // the index of the first time the given boolean expression is
        // false (we consider false to be less than true).  The argmax
        // would return the index of the first time the expression is
        // true.

        Expr escape_condition = Complex(mandelbrot(x, y, r)).magnitude_squared() < 16.0f;
        Tuple first_escape = argmin(escape_condition);

        // We only want the index, not the value, but argmin returns
        // both, so we'll index the argmin Tuple expression using
        // square brackets to get the Expr representing the index.
        Func escape;
        escape(x, y) = first_escape[0];

        // Realize the pipeline and print the result as ascii art.
        Buffer<int> result = escape.realize(61, 25);
        const char *code = " .:-~*={}&%#@";
        for (int y = 0; y < result.height(); y++) {
            for (int x = 0; x < result.width(); x++) {
                printf("%c", code[result(x, y)]);
            }
            printf("\n");
        }
    }

    printf("Success!\n");

    return 0;
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// 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 "default.h"
#include "distribution2d.h"
#include "../common/tutorial/obj_loader.h"
#include "../common/tutorial/xml_loader.h"
#include "../common/image/image.h"

namespace embree
{
  /* name of the tutorial */
  const char* tutorialName = "convert";

  struct HeightField : public RefCount
  {
    HeightField (Ref<Image> texture, const BBox3fa& bounds)
      : texture(texture), bounds(bounds) {}

    const Vec3fa at(const size_t x, const size_t y)
    {
      const size_t width  = texture->width;
      const size_t height = texture->height;
      const Color4 c = texture->get(x,y);
      const Vec2f p(x/(width-1),y/(height-1));
      const float px = p.x*(bounds.upper.x-bounds.lower.x) + bounds.lower.x;
      const float py = c.r;
      const float pz = p.y*(bounds.upper.z-bounds.lower.z) + bounds.lower.z;
      return Vec3fa(px,py,pz);
    }

    const AffineSpace3fa get(Vec2f p)
    {
      const size_t width  = texture->width;
      const size_t height = texture->height;
      const size_t x = clamp((size_t)(p.x*(width-1)),(size_t)0,width-1);
      const size_t y = clamp((size_t)(p.y*(height-1)),(size_t)0,height-1);
      const Color4 c = texture->get(x,y);
      const float px = p.x*(bounds.upper.x-bounds.lower.x) + bounds.lower.x;
      const float py = c.r;
      const float pz = p.y*(bounds.upper.z-bounds.lower.z) + bounds.lower.z;
      return AffineSpace3fa::translate(Vec3fa(px,py,pz));
    }

    Ref<SceneGraph::Node> geometry()
    {
      OBJMaterial material(1.0f,Vec3fa(0.5f),Vec3fa(0.0f),1.0f);
      Ref<SceneGraph::MaterialNode> mnode = new SceneGraph::MaterialNode((Material&)material);
      Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(mnode);

      const size_t width = texture->width;
      const size_t height = texture->height;

      mesh->v.resize(height*width);
      for (size_t y=0; y<height; y++)
        for (size_t x=0; x<width; x++)
          mesh->v[y*width+x] = at(x,y);

      mesh->triangles.resize(2*(height-1)*(width-1));
      for (size_t y=0; y<height-1; y++) {
        for (size_t x=0; x<width-1; x++) {
          const size_t p00 = (y+0)*width+(x+0);
          const size_t p01 = (y+0)*width+(x+1);
          const size_t p10 = (y+1)*width+(x+0);
          const size_t p11 = (y+1)*width+(x+1);
          const size_t tri = y*(width-1)+x;
          mesh->triangles[2*tri+0] = SceneGraph::TriangleMeshNode::Triangle(p00,p01,p10);
          mesh->triangles[2*tri+1] = SceneGraph::TriangleMeshNode::Triangle(p01,p11,p10);
        }
      }
      return mesh.dynamicCast<SceneGraph::Node>();
    }

  private:
    Ref<Image> texture;
    BBox3fa bounds;
  };

  struct Instantiator : public RefCount
  {
    Instantiator(const Ref<HeightField>& heightField,
                               const Ref<SceneGraph::Node>& object, const Ref<Image>& distribution, float minDistance, size_t N)
      : heightField(heightField), object(object), dist(nullptr), minDistance(minDistance), N(N)
    {
      /* create distribution */
      size_t width = distribution->width;
      size_t height = distribution->height;
      float* values = new float[width*height];
      for (size_t y=0; y<height; y++)
        for (size_t x=0; x<width; x++)
          values[y*width+x] = luminance(distribution->get(x,y));
      dist = new Distribution2D(values,width,height);
      delete values;
    }

    void instantiate(Ref<SceneGraph::GroupNode>& group)
    {
      for (size_t i=0; i<N; i++)
      {
        Vec2f r = Vec2f(random<float>(),random<float>());
        Vec2f p = dist->sample(r);
        p.x *= rcp(float(dist->width)); p.y *= rcp(float(dist->height));
        const AffineSpace3fa space = heightField->get(p);
        group->add(new SceneGraph::TransformNode(space,object));
      }
    }

  private:
    Ref<HeightField> heightField;
    Ref<SceneGraph::Node> object;
    Ref<Distribution2D> dist;
    float minDistance;
    size_t N;
  };

  /* scene */
  Ref<SceneGraph::GroupNode> g_scene = new SceneGraph::GroupNode;
  Ref<HeightField> g_height_field = nullptr;

  static void parseCommandLine(Ref<ParseStream> cin, const FileName& path)
  {
    while (true)
    {
      std::string tag = cin->getString();
      if (tag == "") return;

      /* parse command line parameters from a file */
      else if (tag == "-c") {
        FileName file = path + cin->getFileName();
        parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path());
      }

      /* load model */
      else if (tag == "-i") {
        g_scene->add(SceneGraph::load(path + cin->getFileName()));
      }

      /* load terrain */
      else if (tag == "-terrain")
      {
        Ref<Image> tex = loadImage(path + cin->getFileName());
        const Vec3fa lower = cin->getVec3fa();
        const Vec3fa upper = cin->getVec3fa();
        g_height_field = new HeightField(tex,BBox3fa(lower,upper));
        g_scene->add(g_height_field->geometry());
      }

      /* instantiate model */
      else if (tag == "-instantiate") {
        Ref<SceneGraph::Node> object = SceneGraph::load(path + cin->getFileName());
        Ref<Image> distribution = loadImage(path + cin->getFileName());
        const float minDistance = cin->getFloat();
        const size_t N = cin->getInt();
        Ref<Instantiator> instantiator = new Instantiator(g_height_field,object,distribution,minDistance,N);
        instantiator->instantiate(g_scene);
      }

      /* output filename */
      else if (tag == "-o") {
        SceneGraph::store(g_scene.dynamicCast<SceneGraph::Node>(),path + cin->getFileName());
      }

      /* skip unknown command line parameter */
      else {
        std::cerr << "unknown command line parameter: " << tag << " ";
        while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " ";
        std::cerr << std::endl;
      }
    }
  }

  /* main function in embree namespace */
  int main(int argc, char** argv)
  {
    /* create stream for parsing */
    Ref<ParseStream> stream = new ParseStream(new CommandLineStream(argc, argv));

    /* parse command line */
    parseCommandLine(stream, FileName());

    return 0;
  }
}

int main(int argc, char** argv)
{
  try {
    return embree::main(argc, argv);
  }
  catch (const std::exception& e) {
    std::cout << "Error: " << e.what() << std::endl;
    return 1;
  }
  catch (...) {
    std::cout << "Error: unknown exception caught." << std::endl;
    return 1;
  }
}
<commit_msg>bugfix in terrain tessellation<commit_after>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// 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 "default.h"
#include "distribution2d.h"
#include "../common/tutorial/obj_loader.h"
#include "../common/tutorial/xml_loader.h"
#include "../common/image/image.h"

namespace embree
{
  /* name of the tutorial */
  const char* tutorialName = "convert";

  struct HeightField : public RefCount
  {
    HeightField (Ref<Image> texture, const BBox3fa& bounds)
      : texture(texture), bounds(bounds) {}

    const Vec3fa at(const size_t x, const size_t y)
    {
      const size_t width  = texture->width;
      const size_t height = texture->height;
      const Color4 c = texture->get(x,y);
      const Vec2f p(x/float(width-1),y/float(height-1));
      const float px = p.x*(bounds.upper.x-bounds.lower.x) + bounds.lower.x;
      const float py = c.r*(bounds.upper.y-bounds.lower.y) + bounds.lower.y;
      const float pz = p.y*(bounds.upper.z-bounds.lower.z) + bounds.lower.z;
      return Vec3fa(px,py,pz);
    }

    const AffineSpace3fa get(Vec2f p)
    {
      const size_t width  = texture->width;
      const size_t height = texture->height;
      const size_t x = clamp((size_t)(p.x*(width-1)),(size_t)0,width-1);
      const size_t y = clamp((size_t)(p.y*(height-1)),(size_t)0,height-1);
      const Color4 c = texture->get(x,y);
      const float px = p.x*(bounds.upper.x-bounds.lower.x) + bounds.lower.x;
      const float py = c.r*(bounds.upper.y-bounds.lower.y) + bounds.lower.y;
      const float pz = p.y*(bounds.upper.z-bounds.lower.z) + bounds.lower.z;
      return AffineSpace3fa::translate(Vec3fa(px,py,pz));
    }

    Ref<SceneGraph::Node> geometry()
    {
      OBJMaterial material(1.0f,Vec3fa(0.5f),Vec3fa(0.0f),1.0f);
      Ref<SceneGraph::MaterialNode> mnode = new SceneGraph::MaterialNode((Material&)material);
      Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(mnode);

      const size_t width = texture->width;
      const size_t height = texture->height;

      mesh->v.resize(height*width);
      for (size_t y=0; y<height; y++)
        for (size_t x=0; x<width; x++)
          mesh->v[y*width+x] = at(x,y);

      mesh->triangles.resize(2*(height-1)*(width-1));
      for (size_t y=0; y<height-1; y++) {
        for (size_t x=0; x<width-1; x++) {
          const size_t p00 = (y+0)*width+(x+0);
          const size_t p01 = (y+0)*width+(x+1);
          const size_t p10 = (y+1)*width+(x+0);
          const size_t p11 = (y+1)*width+(x+1);
          const size_t tri = y*(width-1)+x;
          mesh->triangles[2*tri+0] = SceneGraph::TriangleMeshNode::Triangle(p00,p01,p10);
          mesh->triangles[2*tri+1] = SceneGraph::TriangleMeshNode::Triangle(p01,p11,p10);
        }
      }
      return mesh.dynamicCast<SceneGraph::Node>();
    }

  private:
    Ref<Image> texture;
    BBox3fa bounds;
  };

  struct Instantiator : public RefCount
  {
    Instantiator(const Ref<HeightField>& heightField,
                               const Ref<SceneGraph::Node>& object, const Ref<Image>& distribution, float minDistance, size_t N)
      : heightField(heightField), object(object), dist(nullptr), minDistance(minDistance), N(N)
    {
      /* create distribution */
      size_t width = distribution->width;
      size_t height = distribution->height;
      float* values = new float[width*height];
      for (size_t y=0; y<height; y++)
        for (size_t x=0; x<width; x++)
          values[y*width+x] = luminance(distribution->get(x,y));
      dist = new Distribution2D(values,width,height);
      delete values;
    }

    void instantiate(Ref<SceneGraph::GroupNode>& group)
    {
      for (size_t i=0; i<N; i++)
      {
        Vec2f r = Vec2f(random<float>(),random<float>());
        Vec2f p = dist->sample(r);
        p.x *= rcp(float(dist->width)); p.y *= rcp(float(dist->height));
        const AffineSpace3fa space = heightField->get(p);
        group->add(new SceneGraph::TransformNode(space,object));
      }
    }

  private:
    Ref<HeightField> heightField;
    Ref<SceneGraph::Node> object;
    Ref<Distribution2D> dist;
    float minDistance;
    size_t N;
  };

  /* scene */
  Ref<SceneGraph::GroupNode> g_scene = new SceneGraph::GroupNode;
  Ref<HeightField> g_height_field = nullptr;

  static void parseCommandLine(Ref<ParseStream> cin, const FileName& path)
  {
    while (true)
    {
      std::string tag = cin->getString();
      if (tag == "") return;

      /* parse command line parameters from a file */
      else if (tag == "-c") {
        FileName file = path + cin->getFileName();
        parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path());
      }

      /* load model */
      else if (tag == "-i") {
        g_scene->add(SceneGraph::load(path + cin->getFileName()));
      }

      /* load terrain */
      else if (tag == "-terrain")
      {
        Ref<Image> tex = loadImage(path + cin->getFileName());
        const Vec3fa lower = cin->getVec3fa();
        const Vec3fa upper = cin->getVec3fa();
        g_height_field = new HeightField(tex,BBox3fa(lower,upper));
        g_scene->add(g_height_field->geometry());
      }

      /* instantiate model */
      else if (tag == "-instantiate") {
        Ref<SceneGraph::Node> object = SceneGraph::load(path + cin->getFileName());
        Ref<Image> distribution = loadImage(path + cin->getFileName());
        const float minDistance = cin->getFloat();
        const size_t N = cin->getInt();
        Ref<Instantiator> instantiator = new Instantiator(g_height_field,object,distribution,minDistance,N);
        instantiator->instantiate(g_scene);
      }

      /* output filename */
      else if (tag == "-o") {
        SceneGraph::store(g_scene.dynamicCast<SceneGraph::Node>(),path + cin->getFileName());
      }

      /* skip unknown command line parameter */
      else {
        std::cerr << "unknown command line parameter: " << tag << " ";
        while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " ";
        std::cerr << std::endl;
      }
    }
  }

  /* main function in embree namespace */
  int main(int argc, char** argv)
  {
    /* create stream for parsing */
    Ref<ParseStream> stream = new ParseStream(new CommandLineStream(argc, argv));

    /* parse command line */
    parseCommandLine(stream, FileName());

    return 0;
  }
}

int main(int argc, char** argv)
{
  try {
    return embree::main(argc, argv);
  }
  catch (const std::exception& e) {
    std::cout << "Error: " << e.what() << std::endl;
    return 1;
  }
  catch (...) {
    std::cout << "Error: unknown exception caught." << std::endl;
    return 1;
  }
}
<|endoftext|>


<commit_before>#define ProofNtuple_cxx

//////////////////////////////////////////////////////////
//
// Example of TSelector implementation to do generic
// processing (filling a simple ntuple, in this case).
// See tutorials/proof/runProof.C, option "ntuple", for an
// example of how to run this selector.
//
//////////////////////////////////////////////////////////

#include "ProofNtuple.h"
#include <TCanvas.h>
#include <TFrame.h>
#include <TPaveText.h>
#include <TMath.h>
#include <TNtuple.h>
#include <TRandom3.h>
#include <TROOT.h>
#include <TString.h>
#include <TStyle.h>
#include <TSystem.h>
#include <TFile.h>
#include <TProofOutputFile.h>

//_____________________________________________________________________________
ProofNtuple::~ProofNtuple()
{
   // Destructor

   SafeDelete(fNtp);
   SafeDelete(fNtp2);
   SafeDelete(fFile);
   SafeDelete(fRandom);
}

//_____________________________________________________________________________
void ProofNtuple::PlotNtuple(TNtuple *ntp, const char *ntptitle)
{
   // Make some plots from the ntuple 'ntp'

   //
   // Create a canvas, with 2 pads
   //
   TCanvas *c1 = new TCanvas(Form("cv-%s", ntp->GetName()), ntptitle,800,10,700,780);
   c1->Divide(1,2);
   TPad *pad1 = (TPad *) c1->GetPad(1);
   TPad *pad2 = (TPad *) c1->GetPad(2);
   //
   // Display a function of one ntuple column imposing a condition
   // on another column.
   pad1->cd();
   pad1->SetGrid();
   pad1->SetLogy();
   pad1->GetFrame()->SetFillColor(15);
   ntp->SetLineColor(1);
   ntp->SetFillStyle(1001);
   ntp->SetFillColor(45);
   ntp->Draw("3*px+2","px**2+py**2>1");
   ntp->SetFillColor(38);
   ntp->Draw("2*px+2","pz>2","same");
   ntp->SetFillColor(5);
   ntp->Draw("1.3*px+2","(px^2+py^2>4) && py>0","same");
   pad1->RedrawAxis();

   //
   // Display a 3-D scatter plot of 3 columns. Superimpose a different selection.
   pad2->cd();
   ntp->Draw("pz:py:px","(pz<10 && pz>6)+(pz<4 && pz>3)");
   ntp->SetMarkerColor(4);
   ntp->Draw("pz:py:px","pz<6 && pz>4","same");
   ntp->SetMarkerColor(5);
   ntp->Draw("pz:py:px","pz<4 && pz>3","same");
   TPaveText *l2 = new TPaveText(0.,0.6,0.9,0.95);
   l2->SetFillColor(42);
   l2->SetTextAlign(12);
   l2->AddText("You can interactively rotate this view in 2 ways:");
   l2->AddText("  - With the RotateCube in clicking in this pad");
   l2->AddText("  - Selecting View with x3d in the View menu");
   l2->Draw();

   // Final update
   c1->cd();
   c1->Update();
}

//_____________________________________________________________________________
void ProofNtuple::Begin(TTree * /*tree*/)
{
   // The Begin() function is called at the start of the query.
   // When running with PROOF Begin() is only called on the client.
   // The tree argument is deprecated (on PROOF 0 is passed).

   TString option = GetOption();

   TNamed *out = (TNamed *) fInput->FindObject("PROOF_NTUPLE_DONT_PLOT");
   if (out) fPlotNtuple = kFALSE;
}

//_____________________________________________________________________________
void ProofNtuple::SlaveBegin(TTree * /*tree*/)
{
   // The SlaveBegin() function is called after the Begin() function.
   // When running with PROOF SlaveBegin() is called on each slave server.
   // The tree argument is deprecated (on PROOF 0 is passed).

   TString option = GetOption();

   // We may be creating a dataset or a merge file: check it
   TNamed *nm = dynamic_cast<TNamed *>(fInput->FindObject("SimpleNtuple.root"));
   if (nm) {
      // Just create the object
      UInt_t opt = TProofOutputFile::kRegister | TProofOutputFile::kOverwrite | TProofOutputFile::kVerify;
      fProofFile = new TProofOutputFile("SimpleNtuple.root",
                                        TProofOutputFile::kDataset, opt, nm->GetTitle());
   } else {
      // For the ntuple, we use the automatic file merging facility
      // Check if an output URL has been given
      TNamed *out = (TNamed *) fInput->FindObject("PROOF_OUTPUTFILE_LOCATION");
      Info("SlaveBegin", "PROOF_OUTPUTFILE_LOCATION: %s", (out ? out->GetTitle() : "undef"));
      fProofFile = new TProofOutputFile("SimpleNtuple.root", (out ? out->GetTitle() : "M"));
      out = (TNamed *) fInput->FindObject("PROOF_OUTPUTFILE");
      if (out) fProofFile->SetOutputFileName(out->GetTitle());
   }

   // Open the file
   fFile = fProofFile->OpenFile("RECREATE");
   if (fFile && fFile->IsZombie()) SafeDelete(fFile);

   // Cannot continue
   if (!fFile) {
      Info("SlaveBegin", "could not create '%s': instance is invalid!", fProofFile->GetName());
      return;
   }

   // Now we create the ntuple
   fNtp = new TNtuple("ntuple","Demo ntuple","px:py:pz:random:i");
   // File resident
   fNtp->SetDirectory(fFile);
   fNtp->AutoSave();

   // Now we create the second ntuple
   fNtp2 = new TNtuple("ntuple2","Demo ntuple2","vx:vy:vz");
   // File resident
   fNtp2->SetDirectory(fFile);
   fNtp2->AutoSave();

   // Should we generate the random numbers or take them from the ntuple ?
   TNamed *unr = (TNamed *) fInput->FindObject("PROOF_USE_NTP_RNDM");
   if (unr) {
      // Get the ntuple from the input list
      if (!(fNtpRndm = dynamic_cast<TNtuple *>(fInput->FindObject("NtpRndm")))) {
         Warning("SlaveBegin",
                 "asked to use rndm ntuple but 'NtpRndm' not found in the"
                 " input list! Using the random generator");
         fInput->Print();
      } else {
         Info("SlaveBegin", "taking randoms from input ntuple 'NtpRndm'");
      }
   }

   // Init the random generator, if required
   if (!fNtpRndm) fRandom = new TRandom3(0);
}

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

   if (!fNtp) return kTRUE;

   // Fill ntuple
   Float_t px, py, random;
   if (fNtpRndm) {
      // Get the entry
      Float_t *ar = fNtpRndm->GetArgs();
      Long64_t ent = entry % fNtpRndm->GetEntries();
      fNtpRndm->GetEntry(ent);
      random = ar[0];
      px = (Float_t) TMath::ErfInverse((Double_t)(ar[1]*2 - 1.)) * TMath::Sqrt(2.);
      py = (Float_t) TMath::ErfInverse((Double_t)(ar[2]*2 - 1.)) * TMath::Sqrt(2.);
   } else if (fRandom) {
      fRandom->Rannor(px,py);
      random = fRandom->Rndm();
   } else {
      Abort("no way to get random numbers! Stop processing", kAbortProcess);
      return kTRUE;
   }
   Float_t pz = px*px + py*py;
   Int_t i = (Int_t) entry;
   fNtp->Fill(px,py,pz,random,i);

   if (!fNtp2) return kTRUE;

   // The second ntuple
   Float_t vz = random * 2. - 1.;
   fNtp2->Fill(px,py,vz);

   return kTRUE;
}

//_____________________________________________________________________________
void ProofNtuple::SlaveTerminate()
{
   // The SlaveTerminate() function is called after all entries or objects
   // have been processed. When running with PROOF SlaveTerminate() is called
   // on each slave server.

   // Write the ntuple to the file
   if (fFile) {
      if (!fNtp) {
         Error("SlaveTerminate", "'ntuple' is undefined!");
         return;
      }
      Bool_t cleanup = kFALSE;
      TDirectory *savedir = gDirectory;
      if (fNtp->GetEntries() > 0) {
         fFile->cd();
         fNtp->Write();
         if (fNtp2 && fNtp2->GetEntries() > 0) fNtp2->Write();
         fProofFile->Print();
         fOutput->Add(fProofFile);
      } else {
         cleanup = kTRUE;
      }
      fNtp->SetDirectory(0);
      if (fNtp2) fNtp2->SetDirectory(0);
      gDirectory = savedir;
      fFile->Close();
      // Cleanup, if needed
      if (cleanup) {
         TUrl uf(*(fFile->GetEndpointUrl()));
         SafeDelete(fFile);
         gSystem->Unlink(uf.GetFile());
         SafeDelete(fProofFile);
      }
   }
}

//_____________________________________________________________________________
void ProofNtuple::Terminate()
{
   // The Terminate() function is the last function to be called during
   // a query. It always runs on the client, it can be used to present
   // the results graphically or save the results to file.

   // Do nothing is not requested (dataset creation run)
   if (!fPlotNtuple) return;

   // Get the ntuple from the file
   if ((fProofFile =
           dynamic_cast<TProofOutputFile*>(fOutput->FindObject("SimpleNtuple.root")))) {

      TString outputFile(fProofFile->GetOutputFileName());
      TString outputName(fProofFile->GetName());
      outputName += ".root";
      Printf("outputFile: %s", outputFile.Data());

      // Read the ntuple from the file
      fFile = TFile::Open(outputFile);
      if (fFile) {
         Printf("Managed to open file: %s", outputFile.Data());
         fNtp = (TNtuple *) fFile->Get("ntuple");
      } else {
         Error("Terminate", "could not open file: %s", outputFile.Data());
      }
      if (!fFile) return;

   } else {
      Error("Terminate", "TProofOutputFile not found");
      return;
   }

   // Plot ntuples
   if (fNtp) PlotNtuple(fNtp, "proof ntuple");

}
<commit_msg>Make sure that there is only one copy of the ntuple in the output file<commit_after>#define ProofNtuple_cxx

//////////////////////////////////////////////////////////
//
// Example of TSelector implementation to do generic
// processing (filling a simple ntuple, in this case).
// See tutorials/proof/runProof.C, option "ntuple", for an
// example of how to run this selector.
//
//////////////////////////////////////////////////////////

#include "ProofNtuple.h"
#include <TCanvas.h>
#include <TFrame.h>
#include <TPaveText.h>
#include <TMath.h>
#include <TNtuple.h>
#include <TRandom3.h>
#include <TROOT.h>
#include <TString.h>
#include <TStyle.h>
#include <TSystem.h>
#include <TFile.h>
#include <TProofOutputFile.h>

//_____________________________________________________________________________
ProofNtuple::~ProofNtuple()
{
   // Destructor

   SafeDelete(fNtp);
   SafeDelete(fNtp2);
   SafeDelete(fFile);
   SafeDelete(fRandom);
}

//_____________________________________________________________________________
void ProofNtuple::PlotNtuple(TNtuple *ntp, const char *ntptitle)
{
   // Make some plots from the ntuple 'ntp'

   //
   // Create a canvas, with 2 pads
   //
   TCanvas *c1 = new TCanvas(Form("cv-%s", ntp->GetName()), ntptitle,800,10,700,780);
   c1->Divide(1,2);
   TPad *pad1 = (TPad *) c1->GetPad(1);
   TPad *pad2 = (TPad *) c1->GetPad(2);
   //
   // Display a function of one ntuple column imposing a condition
   // on another column.
   pad1->cd();
   pad1->SetGrid();
   pad1->SetLogy();
   pad1->GetFrame()->SetFillColor(15);
   ntp->SetLineColor(1);
   ntp->SetFillStyle(1001);
   ntp->SetFillColor(45);
   ntp->Draw("3*px+2","px**2+py**2>1");
   ntp->SetFillColor(38);
   ntp->Draw("2*px+2","pz>2","same");
   ntp->SetFillColor(5);
   ntp->Draw("1.3*px+2","(px^2+py^2>4) && py>0","same");
   pad1->RedrawAxis();

   //
   // Display a 3-D scatter plot of 3 columns. Superimpose a different selection.
   pad2->cd();
   ntp->Draw("pz:py:px","(pz<10 && pz>6)+(pz<4 && pz>3)");
   ntp->SetMarkerColor(4);
   ntp->Draw("pz:py:px","pz<6 && pz>4","same");
   ntp->SetMarkerColor(5);
   ntp->Draw("pz:py:px","pz<4 && pz>3","same");
   TPaveText *l2 = new TPaveText(0.,0.6,0.9,0.95);
   l2->SetFillColor(42);
   l2->SetTextAlign(12);
   l2->AddText("You can interactively rotate this view in 2 ways:");
   l2->AddText("  - With the RotateCube in clicking in this pad");
   l2->AddText("  - Selecting View with x3d in the View menu");
   l2->Draw();

   // Final update
   c1->cd();
   c1->Update();
}

//_____________________________________________________________________________
void ProofNtuple::Begin(TTree * /*tree*/)
{
   // The Begin() function is called at the start of the query.
   // When running with PROOF Begin() is only called on the client.
   // The tree argument is deprecated (on PROOF 0 is passed).

   TString option = GetOption();

   TNamed *out = (TNamed *) fInput->FindObject("PROOF_NTUPLE_DONT_PLOT");
   if (out) fPlotNtuple = kFALSE;
}

//_____________________________________________________________________________
void ProofNtuple::SlaveBegin(TTree * /*tree*/)
{
   // The SlaveBegin() function is called after the Begin() function.
   // When running with PROOF SlaveBegin() is called on each slave server.
   // The tree argument is deprecated (on PROOF 0 is passed).

   TString option = GetOption();

   // We may be creating a dataset or a merge file: check it
   TNamed *nm = dynamic_cast<TNamed *>(fInput->FindObject("SimpleNtuple.root"));
   if (nm) {
      // Just create the object
      UInt_t opt = TProofOutputFile::kRegister | TProofOutputFile::kOverwrite | TProofOutputFile::kVerify;
      fProofFile = new TProofOutputFile("SimpleNtuple.root",
                                        TProofOutputFile::kDataset, opt, nm->GetTitle());
   } else {
      // For the ntuple, we use the automatic file merging facility
      // Check if an output URL has been given
      TNamed *out = (TNamed *) fInput->FindObject("PROOF_OUTPUTFILE_LOCATION");
      Info("SlaveBegin", "PROOF_OUTPUTFILE_LOCATION: %s", (out ? out->GetTitle() : "undef"));
      fProofFile = new TProofOutputFile("SimpleNtuple.root", (out ? out->GetTitle() : "M"));
      out = (TNamed *) fInput->FindObject("PROOF_OUTPUTFILE");
      if (out) fProofFile->SetOutputFileName(out->GetTitle());
   }

   // Open the file
   fFile = fProofFile->OpenFile("RECREATE");
   if (fFile && fFile->IsZombie()) SafeDelete(fFile);

   // Cannot continue
   if (!fFile) {
      Info("SlaveBegin", "could not create '%s': instance is invalid!", fProofFile->GetName());
      return;
   }

   // Now we create the ntuple
   fNtp = new TNtuple("ntuple","Demo ntuple","px:py:pz:random:i");
   // File resident
   fNtp->SetDirectory(fFile);
   fNtp->AutoSave();

   // Now we create the second ntuple
   fNtp2 = new TNtuple("ntuple2","Demo ntuple2","vx:vy:vz");
   // File resident
   fNtp2->SetDirectory(fFile);
   fNtp2->AutoSave();

   // Should we generate the random numbers or take them from the ntuple ?
   TNamed *unr = (TNamed *) fInput->FindObject("PROOF_USE_NTP_RNDM");
   if (unr) {
      // Get the ntuple from the input list
      if (!(fNtpRndm = dynamic_cast<TNtuple *>(fInput->FindObject("NtpRndm")))) {
         Warning("SlaveBegin",
                 "asked to use rndm ntuple but 'NtpRndm' not found in the"
                 " input list! Using the random generator");
         fInput->Print();
      } else {
         Info("SlaveBegin", "taking randoms from input ntuple 'NtpRndm'");
      }
   }

   // Init the random generator, if required
   if (!fNtpRndm) fRandom = new TRandom3(0);
}

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

   if (!fNtp) return kTRUE;

   // Fill ntuple
   Float_t px, py, random;
   if (fNtpRndm) {
      // Get the entry
      Float_t *ar = fNtpRndm->GetArgs();
      Long64_t ent = entry % fNtpRndm->GetEntries();
      fNtpRndm->GetEntry(ent);
      random = ar[0];
      px = (Float_t) TMath::ErfInverse((Double_t)(ar[1]*2 - 1.)) * TMath::Sqrt(2.);
      py = (Float_t) TMath::ErfInverse((Double_t)(ar[2]*2 - 1.)) * TMath::Sqrt(2.);
   } else if (fRandom) {
      fRandom->Rannor(px,py);
      random = fRandom->Rndm();
   } else {
      Abort("no way to get random numbers! Stop processing", kAbortProcess);
      return kTRUE;
   }
   Float_t pz = px*px + py*py;
   Int_t i = (Int_t) entry;
   fNtp->Fill(px,py,pz,random,i);

   if (!fNtp2) return kTRUE;

   // The second ntuple
   Float_t vz = random * 2. - 1.;
   fNtp2->Fill(px,py,vz);

   return kTRUE;
}

//_____________________________________________________________________________
void ProofNtuple::SlaveTerminate()
{
   // The SlaveTerminate() function is called after all entries or objects
   // have been processed. When running with PROOF SlaveTerminate() is called
   // on each slave server.

   // Write the ntuple to the file
   if (fFile) {
      if (!fNtp) {
         Error("SlaveTerminate", "'ntuple' is undefined!");
         return;
      }
      Bool_t cleanup = kFALSE;
      TDirectory *savedir = gDirectory;
      if (fNtp->GetEntries() > 0) {
         fFile->cd();
         fNtp->Write(0, TObject::kOverwrite);
         if (fNtp2 && fNtp2->GetEntries() > 0) fNtp2->Write();
         fProofFile->Print();
         fOutput->Add(fProofFile);
      } else {
         cleanup = kTRUE;
      }
      fNtp->SetDirectory(0);
      if (fNtp2) fNtp2->SetDirectory(0);
      gDirectory = savedir;
      fFile->Close();
      // Cleanup, if needed
      if (cleanup) {
         TUrl uf(*(fFile->GetEndpointUrl()));
         SafeDelete(fFile);
         gSystem->Unlink(uf.GetFile());
         SafeDelete(fProofFile);
      }
   }
}

//_____________________________________________________________________________
void ProofNtuple::Terminate()
{
   // The Terminate() function is the last function to be called during
   // a query. It always runs on the client, it can be used to present
   // the results graphically or save the results to file.

   // Do nothing is not requested (dataset creation run)
   if (!fPlotNtuple) return;

   // Get the ntuple from the file
   if ((fProofFile =
           dynamic_cast<TProofOutputFile*>(fOutput->FindObject("SimpleNtuple.root")))) {

      TString outputFile(fProofFile->GetOutputFileName());
      TString outputName(fProofFile->GetName());
      outputName += ".root";
      Printf("outputFile: %s", outputFile.Data());

      // Read the ntuple from the file
      fFile = TFile::Open(outputFile);
      if (fFile) {
         Printf("Managed to open file: %s", outputFile.Data());
         fNtp = (TNtuple *) fFile->Get("ntuple");
      } else {
         Error("Terminate", "could not open file: %s", outputFile.Data());
      }
      if (!fFile) return;

   } else {
      Error("Terminate", "TProofOutputFile not found");
      return;
   }

   // Plot ntuples
   if (fNtp) PlotNtuple(fNtp, "proof ntuple");

}
<|endoftext|>