<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/ffmpeg_video_decode_engine.h"

#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/task.h"
#include "media/base/buffers.h"
#include "media/base/callback.h"
#include "media/base/limits.h"
#include "media/base/media_switches.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/ffmpeg_util.h"
#include "media/filters/ffmpeg_demuxer.h"

namespace media {

FFmpegVideoDecodeEngine::FFmpegVideoDecodeEngine()
    : codec_context_(NULL),
      av_stream_(NULL),
      event_handler_(NULL) {
}

FFmpegVideoDecodeEngine::~FFmpegVideoDecodeEngine() {
}

void FFmpegVideoDecodeEngine::Initialize(
    MessageLoop* message_loop,
    VideoDecodeEngine::EventHandler* event_handler,
    const VideoCodecConfig& config) {
  // Always try to use three threads for video decoding.  There is little reason
  // not to since current day CPUs tend to be multi-core and we measured
  // performance benefits on older machines such as P4s with hyperthreading.
  //
  // Handling decoding on separate threads also frees up the pipeline thread to
  // continue processing. Although it'd be nice to have the option of a single
  // decoding thread, FFmpeg treats having one thread the same as having zero
  // threads (i.e., avcodec_decode_video() will execute on the calling thread).
  // Yet another reason for having three threads :)
  static const int kDecodeThreads = 3;
  static const int kMaxDecodeThreads = 16;

  av_stream_ = static_cast<AVStream*>(config.opaque_context_);
  codec_context_ = av_stream_->codec;
  codec_context_->flags2 |= CODEC_FLAG2_FAST;  // Enable faster H264 decode.
  // Enable motion vector search (potentially slow), strong deblocking filter
  // for damaged macroblocks, and set our error detection sensitivity.
  codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
  codec_context_->error_recognition = FF_ER_CAREFUL;

  AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);

  // TODO(fbarchard): Improve thread logic based on size / codec.
  int decode_threads = kDecodeThreads;

  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads));
  if ((!threads.empty() &&
      !base::StringToInt(threads, &decode_threads)) ||
      decode_threads < 0 || decode_threads > kMaxDecodeThreads) {
    decode_threads = kDecodeThreads;
  }

  // We don't allocate AVFrame on the stack since different versions of FFmpeg
  // may change the size of AVFrame, causing stack corruption.  The solution is
  // to let FFmpeg allocate the structure via avcodec_alloc_frame().
  av_frame_.reset(avcodec_alloc_frame());
  VideoCodecInfo info;
  info.success_ = false;
  info.provides_buffers_ = false;
  info.stream_info_.surface_type_ = VideoFrame::TYPE_SYSTEM_MEMORY;
  info.stream_info_.surface_format_ = GetSurfaceFormat();
  info.stream_info_.surface_width_ = config.width_;
  info.stream_info_.surface_height_ = config.height_;
  if (codec &&
      avcodec_thread_init(codec_context_, decode_threads) >= 0 &&
      avcodec_open(codec_context_, codec) >= 0 &&
      av_frame_.get()) {
    info.success_ = true;
  }
#if !defined(FF_THREAD_FRAME)
#pragma message ("Warning: Not building with FFmpeg MT.")
#else
#pragma message ("Building with FFmpeg MT.")
#endif
  event_handler_ = event_handler;
  event_handler_->OnInitializeComplete(info);
}

// TODO(fbarchard): Find way to remove this memcpy of the entire image.
static void CopyPlane(size_t plane,
                      scoped_refptr<VideoFrame> video_frame,
                      const AVFrame* frame) {
  DCHECK_EQ(video_frame->width() % 2, 0u);
  const uint8* source = frame->data[plane];
  const size_t source_stride = frame->linesize[plane];
  uint8* dest = video_frame->data(plane);
  const size_t dest_stride = video_frame->stride(plane);
  size_t bytes_per_line = video_frame->width();
  size_t copy_lines = video_frame->height();
  if (plane != VideoFrame::kYPlane) {
    bytes_per_line /= 2;
    if (video_frame->format() == VideoFrame::YV12) {
      copy_lines = (copy_lines + 1) / 2;
    }
  }
  DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride);
  for (size_t i = 0; i < copy_lines; ++i) {
    memcpy(dest, source, bytes_per_line);
    source += source_stride;
    dest += dest_stride;
  }
}

void FFmpegVideoDecodeEngine::EmptyThisBuffer(
    scoped_refptr<Buffer> buffer) {
  DecodeFrame(buffer);
}

void FFmpegVideoDecodeEngine::FillThisBuffer(scoped_refptr<VideoFrame> frame) {
  scoped_refptr<Buffer> buffer;
  event_handler_->OnEmptyBufferCallback(buffer);
}

// Try to decode frame when both input and output are ready.
void FFmpegVideoDecodeEngine::DecodeFrame(scoped_refptr<Buffer> buffer) {
  scoped_refptr<VideoFrame> video_frame;

  // Create a packet for input data.
  // Due to FFmpeg API changes we no longer have const read-only pointers.
  AVPacket packet;
  av_init_packet(&packet);
  packet.data = const_cast<uint8*>(buffer->GetData());
  packet.size = buffer->GetDataSize();

  // Let FFmpeg handle presentation timestamp reordering.
  codec_context_->reordered_opaque = buffer->GetTimestamp().InMicroseconds();

  // This is for codecs not using get_buffer to initialize
  // |av_frame_->reordered_opaque|
  av_frame_->reordered_opaque = codec_context_->reordered_opaque;

  int frame_decoded = 0;
  int result = avcodec_decode_video2(codec_context_,
                                     av_frame_.get(),
                                     &frame_decoded,
                                     &packet);

  // Log the problem if we can't decode a video frame and exit early.
  if (result < 0) {
    LOG(INFO) << "Error decoding a video frame with timestamp: "
              << buffer->GetTimestamp().InMicroseconds() << " us"
              << " , duration: "
              << buffer->GetDuration().InMicroseconds() << " us"
              << " , packet size: "
              << buffer->GetDataSize() << " bytes";
    // TODO(jiesun): call event_handler_->OnError() instead.
    event_handler_->OnFillBufferCallback(video_frame);
    return;
  }

  // If frame_decoded == 0, then no frame was produced.
  if (frame_decoded == 0) {
    if (buffer->IsEndOfStream())  // We had started flushing.
      event_handler_->OnFillBufferCallback(video_frame);
    else
      event_handler_->OnEmptyBufferCallback(buffer);
    return;
  }

  // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675
  // The decoder is in a bad state and not decoding correctly.
  // Checking for NULL avoids a crash in CopyPlane().
  if (!av_frame_->data[VideoFrame::kYPlane] ||
      !av_frame_->data[VideoFrame::kUPlane] ||
      !av_frame_->data[VideoFrame::kVPlane]) {
    // TODO(jiesun): call event_handler_->OnError() instead.
    event_handler_->OnFillBufferCallback(video_frame);
    return;
  }

  // Determine timestamp and calculate the duration based on the repeat picture
  // count.  According to FFmpeg docs, the total duration can be calculated as
  // follows:
  //   duration = (1 / fps) + (repeat_pict) / (2 * fps)
  //            = (2 + repeat_pict) / (2 * fps)
  DCHECK_LE(av_frame_->repeat_pict, 2);  // Sanity check.
  // Even frame rate is fixed, for some streams and codecs, the value of
  // |codec_context_->time_base| and |av_stream_->time_base| are not the
  // inverse of the |av_stream_->r_frame_rate|. They use 1 milli-second as
  // time-base units and use increment of av_packet->pts which is not one.
  // Use the inverse of |av_stream_->r_frame_rate| instead of time_base.
  AVRational doubled_time_base;
  doubled_time_base.den = av_stream_->r_frame_rate.num;
  doubled_time_base.num = av_stream_->r_frame_rate.den;
  doubled_time_base.den *= 2;

  base::TimeDelta timestamp =
      base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque);
  base::TimeDelta duration =
      ConvertTimestamp(doubled_time_base, 2 + av_frame_->repeat_pict);

  VideoFrame::CreateFrame(GetSurfaceFormat(),
                          codec_context_->width,
                          codec_context_->height,
                          timestamp,
                          duration,
                          &video_frame);
  if (!video_frame.get()) {
    // TODO(jiesun): call event_handler_->OnError() instead.
    event_handler_->OnFillBufferCallback(video_frame);
    return;
  }

  // Copy the frame data since FFmpeg reuses internal buffers for AVFrame
  // output, meaning the data is only valid until the next
  // avcodec_decode_video() call.
  // TODO(scherkus): figure out pre-allocation/buffer cycling scheme.
  // TODO(scherkus): is there a cleaner way to figure out the # of planes?
  CopyPlane(VideoFrame::kYPlane, video_frame.get(), av_frame_.get());
  CopyPlane(VideoFrame::kUPlane, video_frame.get(), av_frame_.get());
  CopyPlane(VideoFrame::kVPlane, video_frame.get(), av_frame_.get());

  event_handler_->OnFillBufferCallback(video_frame);
}

void FFmpegVideoDecodeEngine::Uninitialize() {
  // TODO(jiesun): Release buffers when we support buffer recycling.
  event_handler_->OnUninitializeComplete();
}

void FFmpegVideoDecodeEngine::Flush() {
  avcodec_flush_buffers(codec_context_);
  event_handler_->OnFlushComplete();
}

void FFmpegVideoDecodeEngine::Seek() {
  event_handler_->OnSeekComplete();
}

VideoFrame::Format FFmpegVideoDecodeEngine::GetSurfaceFormat() const {
  // J (Motion JPEG) versions of YUV are full range 0..255.
  // Regular (MPEG) YUV is 16..240.
  // For now we will ignore the distinction and treat them the same.
  switch (codec_context_->pix_fmt) {
    case PIX_FMT_YUV420P:
    case PIX_FMT_YUVJ420P:
      return VideoFrame::YV12;
      break;
    case PIX_FMT_YUV422P:
    case PIX_FMT_YUVJ422P:
      return VideoFrame::YV16;
      break;
    default:
      // TODO(scherkus): More formats here?
      return VideoFrame::INVALID;
  }
}

}  // namespace media
<commit_msg>remove pragma message to fix build issue BUG=none TEST=none<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/ffmpeg_video_decode_engine.h"

#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/task.h"
#include "media/base/buffers.h"
#include "media/base/callback.h"
#include "media/base/limits.h"
#include "media/base/media_switches.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/ffmpeg_util.h"
#include "media/filters/ffmpeg_demuxer.h"

namespace media {

FFmpegVideoDecodeEngine::FFmpegVideoDecodeEngine()
    : codec_context_(NULL),
      av_stream_(NULL),
      event_handler_(NULL) {
}

FFmpegVideoDecodeEngine::~FFmpegVideoDecodeEngine() {
}

void FFmpegVideoDecodeEngine::Initialize(
    MessageLoop* message_loop,
    VideoDecodeEngine::EventHandler* event_handler,
    const VideoCodecConfig& config) {
  // Always try to use three threads for video decoding.  There is little reason
  // not to since current day CPUs tend to be multi-core and we measured
  // performance benefits on older machines such as P4s with hyperthreading.
  //
  // Handling decoding on separate threads also frees up the pipeline thread to
  // continue processing. Although it'd be nice to have the option of a single
  // decoding thread, FFmpeg treats having one thread the same as having zero
  // threads (i.e., avcodec_decode_video() will execute on the calling thread).
  // Yet another reason for having three threads :)
  static const int kDecodeThreads = 3;
  static const int kMaxDecodeThreads = 16;

  av_stream_ = static_cast<AVStream*>(config.opaque_context_);
  codec_context_ = av_stream_->codec;
  codec_context_->flags2 |= CODEC_FLAG2_FAST;  // Enable faster H264 decode.
  // Enable motion vector search (potentially slow), strong deblocking filter
  // for damaged macroblocks, and set our error detection sensitivity.
  codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
  codec_context_->error_recognition = FF_ER_CAREFUL;

  AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);

  // TODO(fbarchard): Improve thread logic based on size / codec.
  int decode_threads = kDecodeThreads;

  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads));
  if ((!threads.empty() &&
      !base::StringToInt(threads, &decode_threads)) ||
      decode_threads < 0 || decode_threads > kMaxDecodeThreads) {
    decode_threads = kDecodeThreads;
  }

  // We don't allocate AVFrame on the stack since different versions of FFmpeg
  // may change the size of AVFrame, causing stack corruption.  The solution is
  // to let FFmpeg allocate the structure via avcodec_alloc_frame().
  av_frame_.reset(avcodec_alloc_frame());
  VideoCodecInfo info;
  info.success_ = false;
  info.provides_buffers_ = false;
  info.stream_info_.surface_type_ = VideoFrame::TYPE_SYSTEM_MEMORY;
  info.stream_info_.surface_format_ = GetSurfaceFormat();
  info.stream_info_.surface_width_ = config.width_;
  info.stream_info_.surface_height_ = config.height_;
  if (codec &&
      avcodec_thread_init(codec_context_, decode_threads) >= 0 &&
      avcodec_open(codec_context_, codec) >= 0 &&
      av_frame_.get()) {
    info.success_ = true;
  }
  event_handler_ = event_handler;
  event_handler_->OnInitializeComplete(info);
}

// TODO(fbarchard): Find way to remove this memcpy of the entire image.
static void CopyPlane(size_t plane,
                      scoped_refptr<VideoFrame> video_frame,
                      const AVFrame* frame) {
  DCHECK_EQ(video_frame->width() % 2, 0u);
  const uint8* source = frame->data[plane];
  const size_t source_stride = frame->linesize[plane];
  uint8* dest = video_frame->data(plane);
  const size_t dest_stride = video_frame->stride(plane);
  size_t bytes_per_line = video_frame->width();
  size_t copy_lines = video_frame->height();
  if (plane != VideoFrame::kYPlane) {
    bytes_per_line /= 2;
    if (video_frame->format() == VideoFrame::YV12) {
      copy_lines = (copy_lines + 1) / 2;
    }
  }
  DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride);
  for (size_t i = 0; i < copy_lines; ++i) {
    memcpy(dest, source, bytes_per_line);
    source += source_stride;
    dest += dest_stride;
  }
}

void FFmpegVideoDecodeEngine::EmptyThisBuffer(
    scoped_refptr<Buffer> buffer) {
  DecodeFrame(buffer);
}

void FFmpegVideoDecodeEngine::FillThisBuffer(scoped_refptr<VideoFrame> frame) {
  scoped_refptr<Buffer> buffer;
  event_handler_->OnEmptyBufferCallback(buffer);
}

// Try to decode frame when both input and output are ready.
void FFmpegVideoDecodeEngine::DecodeFrame(scoped_refptr<Buffer> buffer) {
  scoped_refptr<VideoFrame> video_frame;

  // Create a packet for input data.
  // Due to FFmpeg API changes we no longer have const read-only pointers.
  AVPacket packet;
  av_init_packet(&packet);
  packet.data = const_cast<uint8*>(buffer->GetData());
  packet.size = buffer->GetDataSize();

  // Let FFmpeg handle presentation timestamp reordering.
  codec_context_->reordered_opaque = buffer->GetTimestamp().InMicroseconds();

  // This is for codecs not using get_buffer to initialize
  // |av_frame_->reordered_opaque|
  av_frame_->reordered_opaque = codec_context_->reordered_opaque;

  int frame_decoded = 0;
  int result = avcodec_decode_video2(codec_context_,
                                     av_frame_.get(),
                                     &frame_decoded,
                                     &packet);

  // Log the problem if we can't decode a video frame and exit early.
  if (result < 0) {
    LOG(INFO) << "Error decoding a video frame with timestamp: "
              << buffer->GetTimestamp().InMicroseconds() << " us"
              << " , duration: "
              << buffer->GetDuration().InMicroseconds() << " us"
              << " , packet size: "
              << buffer->GetDataSize() << " bytes";
    // TODO(jiesun): call event_handler_->OnError() instead.
    event_handler_->OnFillBufferCallback(video_frame);
    return;
  }

  // If frame_decoded == 0, then no frame was produced.
  if (frame_decoded == 0) {
    if (buffer->IsEndOfStream())  // We had started flushing.
      event_handler_->OnFillBufferCallback(video_frame);
    else
      event_handler_->OnEmptyBufferCallback(buffer);
    return;
  }

  // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675
  // The decoder is in a bad state and not decoding correctly.
  // Checking for NULL avoids a crash in CopyPlane().
  if (!av_frame_->data[VideoFrame::kYPlane] ||
      !av_frame_->data[VideoFrame::kUPlane] ||
      !av_frame_->data[VideoFrame::kVPlane]) {
    // TODO(jiesun): call event_handler_->OnError() instead.
    event_handler_->OnFillBufferCallback(video_frame);
    return;
  }

  // Determine timestamp and calculate the duration based on the repeat picture
  // count.  According to FFmpeg docs, the total duration can be calculated as
  // follows:
  //   duration = (1 / fps) + (repeat_pict) / (2 * fps)
  //            = (2 + repeat_pict) / (2 * fps)
  DCHECK_LE(av_frame_->repeat_pict, 2);  // Sanity check.
  // Even frame rate is fixed, for some streams and codecs, the value of
  // |codec_context_->time_base| and |av_stream_->time_base| are not the
  // inverse of the |av_stream_->r_frame_rate|. They use 1 milli-second as
  // time-base units and use increment of av_packet->pts which is not one.
  // Use the inverse of |av_stream_->r_frame_rate| instead of time_base.
  AVRational doubled_time_base;
  doubled_time_base.den = av_stream_->r_frame_rate.num;
  doubled_time_base.num = av_stream_->r_frame_rate.den;
  doubled_time_base.den *= 2;

  base::TimeDelta timestamp =
      base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque);
  base::TimeDelta duration =
      ConvertTimestamp(doubled_time_base, 2 + av_frame_->repeat_pict);

  VideoFrame::CreateFrame(GetSurfaceFormat(),
                          codec_context_->width,
                          codec_context_->height,
                          timestamp,
                          duration,
                          &video_frame);
  if (!video_frame.get()) {
    // TODO(jiesun): call event_handler_->OnError() instead.
    event_handler_->OnFillBufferCallback(video_frame);
    return;
  }

  // Copy the frame data since FFmpeg reuses internal buffers for AVFrame
  // output, meaning the data is only valid until the next
  // avcodec_decode_video() call.
  // TODO(scherkus): figure out pre-allocation/buffer cycling scheme.
  // TODO(scherkus): is there a cleaner way to figure out the # of planes?
  CopyPlane(VideoFrame::kYPlane, video_frame.get(), av_frame_.get());
  CopyPlane(VideoFrame::kUPlane, video_frame.get(), av_frame_.get());
  CopyPlane(VideoFrame::kVPlane, video_frame.get(), av_frame_.get());

  event_handler_->OnFillBufferCallback(video_frame);
}

void FFmpegVideoDecodeEngine::Uninitialize() {
  // TODO(jiesun): Release buffers when we support buffer recycling.
  event_handler_->OnUninitializeComplete();
}

void FFmpegVideoDecodeEngine::Flush() {
  avcodec_flush_buffers(codec_context_);
  event_handler_->OnFlushComplete();
}

void FFmpegVideoDecodeEngine::Seek() {
  event_handler_->OnSeekComplete();
}

VideoFrame::Format FFmpegVideoDecodeEngine::GetSurfaceFormat() const {
  // J (Motion JPEG) versions of YUV are full range 0..255.
  // Regular (MPEG) YUV is 16..240.
  // For now we will ignore the distinction and treat them the same.
  switch (codec_context_->pix_fmt) {
    case PIX_FMT_YUV420P:
    case PIX_FMT_YUVJ420P:
      return VideoFrame::YV12;
      break;
    case PIX_FMT_YUV422P:
    case PIX_FMT_YUVJ422P:
      return VideoFrame::YV16;
      break;
    default:
      // TODO(scherkus): More formats here?
      return VideoFrame::INVALID;
  }
}

}  // namespace media
<|endoftext|>


<commit_before>#include <string>
#include <sstream>
#include <vector>

#include "Tools/Exception/exception.hpp"

#include "Sparse_matrix.hpp"

using namespace aff3ct;
using namespace aff3ct::tools;

Sparse_matrix
::Sparse_matrix(const size_t n_rows, const size_t n_cols)
: Matrix(n_rows, n_cols),
  row_to_cols(n_rows),
  col_to_rows(n_cols)
{
}

bool Sparse_matrix
::at(const size_t row_index, const size_t col_index) const
{
	auto it = std::find(this->row_to_cols[row_index].begin(), this->row_to_cols[row_index].end(), col_index);
	return (it != this->row_to_cols[row_index].end());
}

void Sparse_matrix
::add_connection(const size_t row_index, const size_t col_index)
{
	check_indexes(row_index, col_index);

	if (at(row_index, col_index))
	{
		std::stringstream message;
		message << "('row_index';'col_index') connection already exists ('row_index' = " << row_index
		        << ", 'col_index' = " << col_index << ").";
		throw runtime_error(__FILE__, __LINE__, __func__, message.str());
	}

	this->row_to_cols[row_index].push_back(col_index);
	this->col_to_rows[col_index].push_back(row_index);

	this->rows_max_degree = std::max(get_rows_max_degree(), row_to_cols[row_index].size());
	this->cols_max_degree = std::max(get_cols_max_degree(), col_to_rows[col_index].size());

	this->n_connections++;
}

void Sparse_matrix
::rm_connection(const size_t row_index, const size_t col_index)
{
	check_indexes(row_index, col_index);

	// delete the link in the row_to_cols vector
	bool row_found = false;
	auto itr = std::find(this->row_to_cols[row_index].begin(), this->row_to_cols[row_index].end(), col_index);
	if (itr != this->row_to_cols[row_index].end())
	{
		row_found = true;
		itr = this->row_to_cols[row_index].erase(itr);

		// check if need to reduce the rows max degree
		if (this->row_to_cols[row_index].size() == (this->rows_max_degree-1))
		{
			bool found = false;
			for (auto i = this->row_to_cols.begin(); i != this->row_to_cols.end(); i++ )
				if (i->size() == this->rows_max_degree)
				{
					found = true;
					break;
				}

			if (!found)
				this->rows_max_degree--;
		}
	}

	// delete the link in the col_to_rows vector
	bool col_found = false;
	auto itc = std::find(this->col_to_rows[col_index].begin(), this->col_to_rows[col_index].end(), row_index);
	if (itc != this->col_to_rows[col_index].end())
	{
		col_found = true;
		this->col_to_rows[col_index].erase(itc);

		// check if need to reduce the cols max degree
		if (this->col_to_rows[col_index].size() == (this->cols_max_degree-1))
		{
			bool found = false;
			for (auto i = this->col_to_rows.begin(); i != this->col_to_rows.end(); i++ )
				if (i->size() == this->cols_max_degree)
				{
					found = true;
					break;
				}

			if (!found)
				this->cols_max_degree--;
		}
	}

	if (row_found != col_found)
	{
		std::stringstream message;
		message << "The connection has been found only in one of the two vectors 'row_to_cols' and 'col_to_rows' "
		        << "('row_index' = " << row_index << ", 'col_index' = " << col_index
		        << ", found in row = " << std::boolalpha << row_found
		        << ", found in col = " << col_found << std::noboolalpha << ").";
		throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
	}
	else if (row_found && col_found)
		this->n_connections--;
	// else the connection has not been found
}

void Sparse_matrix
::parse_connections()
{
	this->n_connections = std::accumulate(row_to_cols.begin(), row_to_cols.end(), (size_t)0,
	                                      [](size_t init, const std::vector<size_t>& a){ return init + a.size();});

	this->rows_max_degree = std::max_element(row_to_cols.begin(), row_to_cols.end(),
	                                         [](const std::vector<size_t>& a, const std::vector<size_t>& b){ return a.size() < b.size();})
	                        ->size();
	this->cols_max_degree = std::max_element(col_to_rows.begin(), col_to_rows.end(),
	                                         [](const std::vector<size_t>& a, const std::vector<size_t>& b){ return a.size() < b.size();})
	                        ->size();
}

void Sparse_matrix
::self_resize(const size_t n_rows, const size_t n_cols, Origin o)
{
	*this = this->resize(n_rows, n_rows, o);
}

Sparse_matrix Sparse_matrix
::resize(const size_t n_rows, const size_t n_cols, Origin o) const
{
	Sparse_matrix resized(n_rows, n_cols);

	// const auto min_r = std::min(n_rows, get_n_rows());
	const auto min_c = std::min(n_cols, get_n_cols());
	// const auto diff_r = get_n_rows() - min_r;
	const auto diff_c = get_n_cols() - min_c;
	const auto diff_n_rows = (int)n_rows - (int)get_n_rows();
	const auto diff_n_cols = (int)n_cols - (int)get_n_cols();

	switch(o)
	{
		case Origin::TOP_LEFT:
		{
			for (size_t c = 0; c < min_c; c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = c;
					const auto row_index = col_to_rows[c][r];
					if (row_index < n_rows)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
		case Origin::TOP_RIGHT:
		{
			for (size_t c = diff_c; c < get_n_cols(); c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = diff_n_cols + c;
					const auto row_index = col_to_rows[c][r];
					if (row_index < n_rows)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
		case Origin::BOTTOM_LEFT:
		{
			for (size_t c = 0; c < min_c; c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = c;
					const auto row_index = diff_n_rows + (int)col_to_rows[c][r];
					if (row_index >= 0)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
		case Origin::BOTTOM_RIGHT:
		{
			for (size_t c = diff_c; c < get_n_cols(); c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = diff_n_cols + c;
					const auto row_index = diff_n_rows + (int)col_to_rows[c][r];
					if (row_index >= 0)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
	}

	resized.parse_connections();

	return resized;
}

Sparse_matrix Sparse_matrix
::transpose() const
{
	Sparse_matrix trans(*this);

	trans.self_transpose();

	return trans;
}

void Sparse_matrix
::self_transpose()
{
	Matrix::self_transpose();

	std::swap(row_to_cols, col_to_rows);
}

Sparse_matrix Sparse_matrix
::turn(Way w) const
{
	Sparse_matrix turned(*this);

	turned.self_turn(w);

	return turned;
}

void Sparse_matrix
::sort_cols_per_density(Sort order)
{
	switch(order)
	{
		case Sort::ASCENDING:
			std::sort(this->col_to_rows.begin(), this->col_to_rows.end(),
			          [](const std::vector<size_t> &i1, const  std::vector<size_t> &i2) { return i1.size() < i2.size(); });
		break;
		case Sort::DESCENDING:
			std::sort(this->col_to_rows.begin(), this->col_to_rows.end(),
		          [](const  std::vector<size_t> &i1, const std::vector<size_t> &i2) { return i1.size() > i2.size(); });
		break;
	}

	for (auto &r : this->row_to_cols)
		r.clear();
	for (size_t i = 0; i < this->col_to_rows.size(); i++)
		for (size_t j = 0; j < this->col_to_rows[i].size(); j++)
			this->row_to_cols[this->col_to_rows[i][j]].push_back(i);
}

void Sparse_matrix
::print(bool transpose, std::ostream& os) const
{
	if (transpose)
	{
		std::vector<unsigned> rows(get_n_rows(), 0);

		for (auto& col : this->col_to_rows)
		{
			// set the ones
			for (auto& row : col)
				rows[row] = 1;

			for (auto& row : rows)
				os << row << " ";

			os << std::endl;

			// reset the ones
			for (auto& row : col)
				rows[row] = 0;
		}
	}
	else
	{
		std::vector<unsigned> columns(get_n_cols(), 0);

		for (auto& row : this->row_to_cols)
		{
			// set the ones
			for (auto& col : row)
				columns[col] = 1;

			for (auto& col : columns)
				os << col << " ";

			os << std::endl;

			// reset the ones
			for (auto& col : row)
				columns[col] = 0;
		}
	}
}

Sparse_matrix Sparse_matrix
::identity(const size_t n_rows, const size_t n_cols)
{
	Sparse_matrix mat(n_rows, n_cols);
	auto shortest_side = std::min(n_rows, n_cols);

	for (size_t i = 0; i < shortest_side; i++)
		mat.add_connection(i,i);

	return mat;
}

Sparse_matrix Sparse_matrix
::zero(const size_t n_rows, const size_t n_cols)
{
	return Sparse_matrix(n_rows, n_cols);
}<commit_msg>Add 'numeric' include for windows compilo<commit_after>#include <string>
#include <sstream>
#include <vector>
#include <numeric>

#include "Tools/Exception/exception.hpp"

#include "Sparse_matrix.hpp"

using namespace aff3ct;
using namespace aff3ct::tools;

Sparse_matrix
::Sparse_matrix(const size_t n_rows, const size_t n_cols)
: Matrix(n_rows, n_cols),
  row_to_cols(n_rows),
  col_to_rows(n_cols)
{
}

bool Sparse_matrix
::at(const size_t row_index, const size_t col_index) const
{
	auto it = std::find(this->row_to_cols[row_index].begin(), this->row_to_cols[row_index].end(), col_index);
	return (it != this->row_to_cols[row_index].end());
}

void Sparse_matrix
::add_connection(const size_t row_index, const size_t col_index)
{
	check_indexes(row_index, col_index);

	if (at(row_index, col_index))
	{
		std::stringstream message;
		message << "('row_index';'col_index') connection already exists ('row_index' = " << row_index
		        << ", 'col_index' = " << col_index << ").";
		throw runtime_error(__FILE__, __LINE__, __func__, message.str());
	}

	this->row_to_cols[row_index].push_back(col_index);
	this->col_to_rows[col_index].push_back(row_index);

	this->rows_max_degree = std::max(get_rows_max_degree(), row_to_cols[row_index].size());
	this->cols_max_degree = std::max(get_cols_max_degree(), col_to_rows[col_index].size());

	this->n_connections++;
}

void Sparse_matrix
::rm_connection(const size_t row_index, const size_t col_index)
{
	check_indexes(row_index, col_index);

	// delete the link in the row_to_cols vector
	bool row_found = false;
	auto itr = std::find(this->row_to_cols[row_index].begin(), this->row_to_cols[row_index].end(), col_index);
	if (itr != this->row_to_cols[row_index].end())
	{
		row_found = true;
		itr = this->row_to_cols[row_index].erase(itr);

		// check if need to reduce the rows max degree
		if (this->row_to_cols[row_index].size() == (this->rows_max_degree-1))
		{
			bool found = false;
			for (auto i = this->row_to_cols.begin(); i != this->row_to_cols.end(); i++ )
				if (i->size() == this->rows_max_degree)
				{
					found = true;
					break;
				}

			if (!found)
				this->rows_max_degree--;
		}
	}

	// delete the link in the col_to_rows vector
	bool col_found = false;
	auto itc = std::find(this->col_to_rows[col_index].begin(), this->col_to_rows[col_index].end(), row_index);
	if (itc != this->col_to_rows[col_index].end())
	{
		col_found = true;
		this->col_to_rows[col_index].erase(itc);

		// check if need to reduce the cols max degree
		if (this->col_to_rows[col_index].size() == (this->cols_max_degree-1))
		{
			bool found = false;
			for (auto i = this->col_to_rows.begin(); i != this->col_to_rows.end(); i++ )
				if (i->size() == this->cols_max_degree)
				{
					found = true;
					break;
				}

			if (!found)
				this->cols_max_degree--;
		}
	}

	if (row_found != col_found)
	{
		std::stringstream message;
		message << "The connection has been found only in one of the two vectors 'row_to_cols' and 'col_to_rows' "
		        << "('row_index' = " << row_index << ", 'col_index' = " << col_index
		        << ", found in row = " << std::boolalpha << row_found
		        << ", found in col = " << col_found << std::noboolalpha << ").";
		throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
	}
	else if (row_found && col_found)
		this->n_connections--;
	// else the connection has not been found
}

void Sparse_matrix
::parse_connections()
{
	this->n_connections = std::accumulate(row_to_cols.begin(), row_to_cols.end(), (size_t)0,
	                                      [](size_t init, const std::vector<size_t>& a){ return init + a.size();});

	this->rows_max_degree = std::max_element(row_to_cols.begin(), row_to_cols.end(),
	                                         [](const std::vector<size_t>& a, const std::vector<size_t>& b){ return a.size() < b.size();})
	                        ->size();
	this->cols_max_degree = std::max_element(col_to_rows.begin(), col_to_rows.end(),
	                                         [](const std::vector<size_t>& a, const std::vector<size_t>& b){ return a.size() < b.size();})
	                        ->size();
}

void Sparse_matrix
::self_resize(const size_t n_rows, const size_t n_cols, Origin o)
{
	*this = this->resize(n_rows, n_rows, o);
}

Sparse_matrix Sparse_matrix
::resize(const size_t n_rows, const size_t n_cols, Origin o) const
{
	Sparse_matrix resized(n_rows, n_cols);

	// const auto min_r = std::min(n_rows, get_n_rows());
	const auto min_c = std::min(n_cols, get_n_cols());
	// const auto diff_r = get_n_rows() - min_r;
	const auto diff_c = get_n_cols() - min_c;
	const auto diff_n_rows = (int)n_rows - (int)get_n_rows();
	const auto diff_n_cols = (int)n_cols - (int)get_n_cols();

	switch(o)
	{
		case Origin::TOP_LEFT:
		{
			for (size_t c = 0; c < min_c; c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = c;
					const auto row_index = col_to_rows[c][r];
					if (row_index < n_rows)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
		case Origin::TOP_RIGHT:
		{
			for (size_t c = diff_c; c < get_n_cols(); c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = diff_n_cols + c;
					const auto row_index = col_to_rows[c][r];
					if (row_index < n_rows)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
		case Origin::BOTTOM_LEFT:
		{
			for (size_t c = 0; c < min_c; c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = c;
					const auto row_index = diff_n_rows + (int)col_to_rows[c][r];
					if (row_index >= 0)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
		case Origin::BOTTOM_RIGHT:
		{
			for (size_t c = diff_c; c < get_n_cols(); c++)
				for (size_t r = 0; r < col_to_rows[c].size(); r++)
				{
					const auto col_index = diff_n_cols + c;
					const auto row_index = diff_n_rows + (int)col_to_rows[c][r];
					if (row_index >= 0)
					{
						resized.row_to_cols[row_index].push_back(col_index);
						resized.col_to_rows[col_index].push_back(row_index);
					}
				}
		}
		break;
	}

	resized.parse_connections();

	return resized;
}

Sparse_matrix Sparse_matrix
::transpose() const
{
	Sparse_matrix trans(*this);

	trans.self_transpose();

	return trans;
}

void Sparse_matrix
::self_transpose()
{
	Matrix::self_transpose();

	std::swap(row_to_cols, col_to_rows);
}

Sparse_matrix Sparse_matrix
::turn(Way w) const
{
	Sparse_matrix turned(*this);

	turned.self_turn(w);

	return turned;
}

void Sparse_matrix
::sort_cols_per_density(Sort order)
{
	switch(order)
	{
		case Sort::ASCENDING:
			std::sort(this->col_to_rows.begin(), this->col_to_rows.end(),
			          [](const std::vector<size_t> &i1, const  std::vector<size_t> &i2) { return i1.size() < i2.size(); });
		break;
		case Sort::DESCENDING:
			std::sort(this->col_to_rows.begin(), this->col_to_rows.end(),
		          [](const  std::vector<size_t> &i1, const std::vector<size_t> &i2) { return i1.size() > i2.size(); });
		break;
	}

	for (auto &r : this->row_to_cols)
		r.clear();
	for (size_t i = 0; i < this->col_to_rows.size(); i++)
		for (size_t j = 0; j < this->col_to_rows[i].size(); j++)
			this->row_to_cols[this->col_to_rows[i][j]].push_back(i);
}

void Sparse_matrix
::print(bool transpose, std::ostream& os) const
{
	if (transpose)
	{
		std::vector<unsigned> rows(get_n_rows(), 0);

		for (auto& col : this->col_to_rows)
		{
			// set the ones
			for (auto& row : col)
				rows[row] = 1;

			for (auto& row : rows)
				os << row << " ";

			os << std::endl;

			// reset the ones
			for (auto& row : col)
				rows[row] = 0;
		}
	}
	else
	{
		std::vector<unsigned> columns(get_n_cols(), 0);

		for (auto& row : this->row_to_cols)
		{
			// set the ones
			for (auto& col : row)
				columns[col] = 1;

			for (auto& col : columns)
				os << col << " ";

			os << std::endl;

			// reset the ones
			for (auto& col : row)
				columns[col] = 0;
		}
	}
}

Sparse_matrix Sparse_matrix
::identity(const size_t n_rows, const size_t n_cols)
{
	Sparse_matrix mat(n_rows, n_cols);
	auto shortest_side = std::min(n_rows, n_cols);

	for (size_t i = 0; i < shortest_side; i++)
		mat.add_connection(i,i);

	return mat;
}

Sparse_matrix Sparse_matrix
::zero(const size_t n_rows, const size_t n_cols)
{
	return Sparse_matrix(n_rows, n_cols);
}<|endoftext|>


<commit_before>// Program.cpp (Oclgrind)
// Copyright (c) 2013-2014, James Price and Simon McIntosh-Smith,
// University of Bristol. All rights reserved.
//
// This program is provided under a three-clause BSD license. For full
// license terms please see the LICENSE file distributed with this
// source code.

#include "common.h"
#include <fstream>

#include "llvm/Assembly/AssemblyAnnotationWriter.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/system_error.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Scalar.h"
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>

#include "Kernel.h"
#include "Program.h"
#include "WorkItem.h"

#define ENV_DUMP "OCLGRIND_DUMP_TEMPS"
#define CL_DUMP_NAME "/tmp/oclgrind_%lX.cl"
#define IR_DUMP_NAME "/tmp/oclgrind_%lX.s"
#define BC_DUMP_NAME "/tmp/oclgrind_%lX.bc"

#if defined(_WIN32)
#define REMAP_DIR "Z:/remapped/"
#else
#define REMAP_DIR "/remapped/"
#endif

#define REMAP_INPUT "input.cl"
#define CLC_H_PATH REMAP_DIR"clc.h"
extern const char CLC_H_DATA[];

using namespace spirsim;
using namespace std;

Program::Program(llvm::Module *module)
  : m_module(module)
{
  m_action = NULL;
  m_buildLog = "";
  m_buildOptions = "";
  m_buildStatus = CL_BUILD_SUCCESS;
  m_uid = generateUID();
}

Program::Program(const string& source)
{
  m_source = source;
  m_module = NULL;
  m_action = NULL;
  m_buildLog = "";
  m_buildOptions = "";
  m_buildStatus = CL_BUILD_NONE;
  m_uid = 0;
}

Program::~Program()
{
  WorkItem::InterpreterCache::clear(m_uid);

  if (m_module)
  {
    delete m_module;
  }

  if (m_action)
  {
    delete m_action;
  }
}

bool Program::build(const char *options, list<Header> headers)
{
  m_buildStatus = CL_BUILD_IN_PROGRESS;
  m_buildOptions = options ? options : "";

  // Create build log
  m_buildLog = "";
  llvm::raw_string_ostream buildLog(m_buildLog);

  // Do nothing if program was created with binary
  if (m_source.empty() && m_module)
  {
    m_buildStatus = CL_BUILD_SUCCESS;
    return true;
  }

  if (m_module)
  {
    delete m_module;
    m_module = NULL;

    WorkItem::InterpreterCache::clear(m_uid);
  }

  // Assign a new UID to this program
  m_uid = generateUID();

  // Set compiler arguments
  vector<const char*> args;
  args.push_back("-D cl_khr_fp64");
  args.push_back("-cl-kernel-arg-info");
  args.push_back("-triple");
  args.push_back("spir64-unknown-unknown");
  args.push_back("-g");

  // Disable optimizations by default due to bugs in Khronos SPIR generator
  bool optimize = false;
  args.push_back("-O0");

  // Add OpenCL build options
  if (options)
  {
    char *_options = strdup(options);
    char *opt = strtok(_options, " ");
    while (opt)
    {
      // Ignore options that break PCH
      if (strcmp(opt, "-cl-fast-relaxed-math") != 0 &&
          strcmp(opt, "-cl-single-precision-constant") != 0)
      {
        args.push_back(opt);

        // Check for optimization flags
        if (strncmp(opt, "-O", 2) == 0)
        {
          if (strcmp(opt, "-O0") == 0)
          {
            optimize = false;
          }
          else
          {
            optimize = true;
          }
        }
      }
      opt = strtok(NULL, " ");
    }
  }

  // Select precompiled header
  const char *pch = NULL;
  if (optimize)
  {
    pch = INSTALL_ROOT"/include/spirsim/clc.pch";
  }
  else
  {
    pch = INSTALL_ROOT"/include/spirsim/clc.noopt.pch";
  }

  // Use precompiled header if it exists, otherwise fall back to embedded clc.h
  ifstream pchfile(pch);
  if (pchfile.good())
  {
    args.push_back("-include-pch");
    args.push_back(pch);
  }
  else
  {
    args.push_back("-include");
    args.push_back(CLC_H_PATH);
    buildLog << "WARNING: Unable to find precompiled header.\n";
  }
  pchfile.close();

  // Append input file to arguments (remapped later)
  args.push_back(REMAP_INPUT);

  // Create diagnostics engine
  clang::DiagnosticOptions *diagOpts = new clang::DiagnosticOptions();
  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
    new clang::DiagnosticIDs());
  clang::TextDiagnosticPrinter diagConsumer(buildLog, diagOpts);
  clang::DiagnosticsEngine diags(diagID, diagOpts, &diagConsumer, false);

  // Create compiler invocation
  llvm::OwningPtr<clang::CompilerInvocation> invocation(
    new clang::CompilerInvocation);
  clang::CompilerInvocation::CreateFromArgs(*invocation,
                                            &args[0], &args[0] + args.size(),
                                            diags);

  // Create compiler instance
  clang::CompilerInstance compiler;
  compiler.setInvocation(invocation.take());

  // Remap include files
  llvm::MemoryBuffer *buffer;
  compiler.getHeaderSearchOpts().AddPath(REMAP_DIR, clang::frontend::Quoted,
                                         false, false, false);
  list<Header>::iterator itr;
  for (itr = headers.begin(); itr != headers.end(); itr++)
  {
    buffer = llvm::MemoryBuffer::getMemBuffer(itr->second->m_source, "", false);
    compiler.getPreprocessorOpts().addRemappedFile(REMAP_DIR + itr->first,
                                                   buffer);
  }

  // Remap clc.h
  buffer = llvm::MemoryBuffer::getMemBuffer(CLC_H_DATA, "", false);
  compiler.getPreprocessorOpts().addRemappedFile(CLC_H_PATH, buffer);

  // Remap input file
  buffer = llvm::MemoryBuffer::getMemBuffer(m_source, "", false);
  compiler.getPreprocessorOpts().addRemappedFile(REMAP_INPUT, buffer);

  // Prepare diagnostics
  compiler.createDiagnostics(args.size(), &args[0], &diagConsumer, false);
  if (!compiler.hasDiagnostics())
  {
    m_buildStatus = CL_BUILD_ERROR;
    return false;
  }

  // Compile
  llvm::LLVMContext& context = llvm::getGlobalContext();
  clang::CodeGenAction *action = new clang::EmitLLVMOnlyAction(&context);

  if (compiler.ExecuteAction(*action))
  {
    // Retrieve module
    m_action = new llvm::OwningPtr<clang::CodeGenAction>(action);
    m_module = action->takeModule();
    m_buildStatus = CL_BUILD_SUCCESS;
  }
  else
  {
    m_buildStatus = CL_BUILD_ERROR;
  }

  // Dump temps if required
  const char *keepTempsEnv = getenv(ENV_DUMP);
  if (keepTempsEnv && strcmp(keepTempsEnv, "1") == 0)
  {
    // Construct unique filenames
    char *tempCL = new char[strlen(CL_DUMP_NAME) + 17];
    char *tempIR = new char[strlen(IR_DUMP_NAME) + 17];
    char *tempBC = new char[strlen(BC_DUMP_NAME) + 17];
    sprintf(tempCL, CL_DUMP_NAME, m_uid);
    sprintf(tempIR, IR_DUMP_NAME, m_uid);
    sprintf(tempBC, BC_DUMP_NAME, m_uid);

    // Dump source
    ofstream cl;
    cl.open(tempCL);
    cl << m_source;
    cl.close();

    if (m_buildStatus == CL_BUILD_SUCCESS)
    {
      // Dump IR
      string err;
      llvm::raw_fd_ostream ir(tempIR, err);
      llvm::AssemblyAnnotationWriter asmWriter;
      m_module->print(ir, &asmWriter);
      ir.close();

      // Dump bitcode
      llvm::raw_fd_ostream bc(tempBC, err);
      llvm::WriteBitcodeToFile(m_module, bc);
      bc.close();
    }

    delete[] tempCL;
    delete[] tempIR;
    delete[] tempBC;
  }

  return m_buildStatus == CL_BUILD_SUCCESS;
}

Program* Program::createFromBitcode(const unsigned char *bitcode,
                                    size_t length)
{
  // Load bitcode from file
  llvm::MemoryBuffer *buffer;
  llvm::StringRef data((const char*)bitcode, length);
  buffer = llvm::MemoryBuffer::getMemBuffer(data, "", false);
  if (!buffer)
  {
    return NULL;
  }

  // Parse bitcode into IR module
  llvm::LLVMContext& context = llvm::getGlobalContext();
  llvm::Module *module = ParseBitcodeFile(buffer, context);
  if (!module)
  {
    return NULL;
  }

  return new Program(module);
}

Program* Program::createFromBitcodeFile(const string filename)
{
  // Load bitcode from file
  llvm::OwningPtr<llvm::MemoryBuffer> buffer;
  if (llvm::MemoryBuffer::getFile(filename, buffer))
  {
    return NULL;
  }

  // Parse bitcode into IR module
  llvm::LLVMContext& context = llvm::getGlobalContext();
  llvm::Module *module = ParseBitcodeFile(buffer.get(), context);
  if (!module)
  {
    return NULL;
  }

  return new Program(module);
}

Program* Program::createFromPrograms(list<const Program*> programs)
{
  llvm::LLVMContext& context = llvm::getGlobalContext();
  llvm::Module *module = new llvm::Module("oclgrind_linked", context);
  llvm::Linker linker("oclgrind", module);

  // Link modules
  list<const Program*>::iterator itr;
  for (itr = programs.begin(); itr != programs.end(); itr++)
  {
    if (linker.LinkInModule(CloneModule((*itr)->m_module)))
    {
      return NULL;
    }
  }

  return new Program(linker.releaseModule());
}

Kernel* Program::createKernel(const string name)
{
  // Iterate over functions in module to find kernel
  llvm::Function *function = NULL;
  llvm::Module::iterator funcItr;
  for(funcItr = m_module->begin(); funcItr != m_module->end(); funcItr++)
  {
    // Check kernel name
    if (funcItr->getName().str() != name)
      continue;

    function = funcItr;
    break;
  }
  if (function == NULL)
  {
    return NULL;
  }

  // Assign identifiers to unnamed temporaries
  llvm::FunctionPass *instNamer = llvm::createInstructionNamerPass();
  instNamer->runOnFunction(*((llvm::Function*)function));
  delete instNamer;

  try
  {
    return new Kernel(*this, function, m_module);
  }
  catch (FatalError& err)
  {
    cerr << endl << "OCLGRIND FATAL ERROR "
         << "(" << err.getFile() << ":" << err.getLine() << ")"
         << endl << err.what()
         << endl << "When creating kernel '" << name << "'"
         << endl;
    return NULL;
  }
}

unsigned char* Program::getBinary() const
{
  if (!m_module)
  {
    return NULL;
  }

  std::string str;
  llvm::raw_string_ostream stream(str);
  llvm::WriteBitcodeToFile(m_module, stream);
  stream.str();
  unsigned char *bitcode = new unsigned char[str.length()];
  memcpy(bitcode, str.c_str(), str.length());
  return bitcode;
}

size_t Program::getBinarySize() const
{
  if (!m_module)
  {
    return 0;
  }

  std::string str;
  llvm::raw_string_ostream stream(str);
  llvm::WriteBitcodeToFile(m_module, stream);
  stream.str();
  return str.length();
}

const string& Program::getBuildLog() const
{
  return m_buildLog;
}

const string& Program::getBuildOptions() const
{
  return m_buildOptions;
}

unsigned int Program::getBuildStatus() const
{
  return m_buildStatus;
}

unsigned long Program::generateUID() const
{
  srand(now());
  return rand();
}

list<string> Program::getKernelNames() const
{
  list<string> names;

  // Iterate over functions in module to find kernels
  unsigned int num = 0;
  llvm::Function *function = NULL;
  llvm::Module::iterator funcItr;
  for(funcItr = m_module->begin(); funcItr != m_module->end(); funcItr++)
  {
    if (funcItr->getCallingConv() == llvm::CallingConv::SPIR_KERNEL)
    {
      names.push_back(funcItr->getName().str());
    }
  }

  return names;
}

unsigned int Program::getNumKernels() const
{
  assert(m_module != NULL);

  // Iterate over functions in module to find kernels
  unsigned int num = 0;
  llvm::Function *function = NULL;
  llvm::Module::iterator funcItr;
  for(funcItr = m_module->begin(); funcItr != m_module->end(); funcItr++)
  {
    if (funcItr->getCallingConv() == llvm::CallingConv::SPIR_KERNEL)
    {
      num++;
    }
  }

  return num;
}

const string& Program::getSource() const
{
  return m_source;
}

unsigned long Program::getUID() const
{
  return m_uid;
}
<commit_msg>Using %TEMP% for dumping build output on Windows.<commit_after>// Program.cpp (Oclgrind)
// Copyright (c) 2013-2014, James Price and Simon McIntosh-Smith,
// University of Bristol. All rights reserved.
//
// This program is provided under a three-clause BSD license. For full
// license terms please see the LICENSE file distributed with this
// source code.

#include "common.h"
#include <fstream>

#include "llvm/Assembly/AssemblyAnnotationWriter.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/system_error.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Scalar.h"
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>

#include "Kernel.h"
#include "Program.h"
#include "WorkItem.h"

#define ENV_DUMP "OCLGRIND_DUMP_TEMPS"
#define CL_DUMP_NAME "/tmp/oclgrind_%lX.cl"
#define IR_DUMP_NAME "/tmp/oclgrind_%lX.s"
#define BC_DUMP_NAME "/tmp/oclgrind_%lX.bc"

#if defined(_WIN32)
#define REMAP_DIR "Z:/remapped/"
#else
#define REMAP_DIR "/remapped/"
#endif

#define REMAP_INPUT "input.cl"
#define CLC_H_PATH REMAP_DIR"clc.h"
extern const char CLC_H_DATA[];

using namespace spirsim;
using namespace std;

Program::Program(llvm::Module *module)
  : m_module(module)
{
  m_action = NULL;
  m_buildLog = "";
  m_buildOptions = "";
  m_buildStatus = CL_BUILD_SUCCESS;
  m_uid = generateUID();
}

Program::Program(const string& source)
{
  m_source = source;
  m_module = NULL;
  m_action = NULL;
  m_buildLog = "";
  m_buildOptions = "";
  m_buildStatus = CL_BUILD_NONE;
  m_uid = 0;
}

Program::~Program()
{
  WorkItem::InterpreterCache::clear(m_uid);

  if (m_module)
  {
    delete m_module;
  }

  if (m_action)
  {
    delete m_action;
  }
}

bool Program::build(const char *options, list<Header> headers)
{
  m_buildStatus = CL_BUILD_IN_PROGRESS;
  m_buildOptions = options ? options : "";

  // Create build log
  m_buildLog = "";
  llvm::raw_string_ostream buildLog(m_buildLog);

  // Do nothing if program was created with binary
  if (m_source.empty() && m_module)
  {
    m_buildStatus = CL_BUILD_SUCCESS;
    return true;
  }

  if (m_module)
  {
    delete m_module;
    m_module = NULL;

    WorkItem::InterpreterCache::clear(m_uid);
  }

  // Assign a new UID to this program
  m_uid = generateUID();

  // Set compiler arguments
  vector<const char*> args;
  args.push_back("-D cl_khr_fp64");
  args.push_back("-cl-kernel-arg-info");
  args.push_back("-triple");
  args.push_back("spir64-unknown-unknown");
  args.push_back("-g");

  // Disable optimizations by default due to bugs in Khronos SPIR generator
  bool optimize = false;
  args.push_back("-O0");

  // Add OpenCL build options
  if (options)
  {
    char *_options = strdup(options);
    char *opt = strtok(_options, " ");
    while (opt)
    {
      // Ignore options that break PCH
      if (strcmp(opt, "-cl-fast-relaxed-math") != 0 &&
          strcmp(opt, "-cl-single-precision-constant") != 0)
      {
        args.push_back(opt);

        // Check for optimization flags
        if (strncmp(opt, "-O", 2) == 0)
        {
          if (strcmp(opt, "-O0") == 0)
          {
            optimize = false;
          }
          else
          {
            optimize = true;
          }
        }
      }
      opt = strtok(NULL, " ");
    }
  }

  // Select precompiled header
  const char *pch = NULL;
  if (optimize)
  {
    pch = INSTALL_ROOT"/include/spirsim/clc.pch";
  }
  else
  {
    pch = INSTALL_ROOT"/include/spirsim/clc.noopt.pch";
  }

  // Use precompiled header if it exists, otherwise fall back to embedded clc.h
  ifstream pchfile(pch);
  if (pchfile.good())
  {
    args.push_back("-include-pch");
    args.push_back(pch);
  }
  else
  {
    args.push_back("-include");
    args.push_back(CLC_H_PATH);
    buildLog << "WARNING: Unable to find precompiled header.\n";
  }
  pchfile.close();

  // Append input file to arguments (remapped later)
  args.push_back(REMAP_INPUT);

  // Create diagnostics engine
  clang::DiagnosticOptions *diagOpts = new clang::DiagnosticOptions();
  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
    new clang::DiagnosticIDs());
  clang::TextDiagnosticPrinter diagConsumer(buildLog, diagOpts);
  clang::DiagnosticsEngine diags(diagID, diagOpts, &diagConsumer, false);

  // Create compiler invocation
  llvm::OwningPtr<clang::CompilerInvocation> invocation(
    new clang::CompilerInvocation);
  clang::CompilerInvocation::CreateFromArgs(*invocation,
                                            &args[0], &args[0] + args.size(),
                                            diags);

  // Create compiler instance
  clang::CompilerInstance compiler;
  compiler.setInvocation(invocation.take());

  // Remap include files
  llvm::MemoryBuffer *buffer;
  compiler.getHeaderSearchOpts().AddPath(REMAP_DIR, clang::frontend::Quoted,
                                         false, false, false);
  list<Header>::iterator itr;
  for (itr = headers.begin(); itr != headers.end(); itr++)
  {
    buffer = llvm::MemoryBuffer::getMemBuffer(itr->second->m_source, "", false);
    compiler.getPreprocessorOpts().addRemappedFile(REMAP_DIR + itr->first,
                                                   buffer);
  }

  // Remap clc.h
  buffer = llvm::MemoryBuffer::getMemBuffer(CLC_H_DATA, "", false);
  compiler.getPreprocessorOpts().addRemappedFile(CLC_H_PATH, buffer);

  // Remap input file
  buffer = llvm::MemoryBuffer::getMemBuffer(m_source, "", false);
  compiler.getPreprocessorOpts().addRemappedFile(REMAP_INPUT, buffer);

  // Prepare diagnostics
  compiler.createDiagnostics(args.size(), &args[0], &diagConsumer, false);
  if (!compiler.hasDiagnostics())
  {
    m_buildStatus = CL_BUILD_ERROR;
    return false;
  }

  // Compile
  llvm::LLVMContext& context = llvm::getGlobalContext();
  clang::CodeGenAction *action = new clang::EmitLLVMOnlyAction(&context);

  if (compiler.ExecuteAction(*action))
  {
    // Retrieve module
    m_action = new llvm::OwningPtr<clang::CodeGenAction>(action);
    m_module = action->takeModule();
    m_buildStatus = CL_BUILD_SUCCESS;
  }
  else
  {
    m_buildStatus = CL_BUILD_ERROR;
  }

  // Dump temps if required
  const char *keepTempsEnv = getenv(ENV_DUMP);
  if (keepTempsEnv && strcmp(keepTempsEnv, "1") == 0)
  {
    // Temporary directory
#if defined(_WIN32)
    const char *tmpdir = getenv("TEMP");
#else
    const char *tmpdir = "/tmp";
#endif

    // Construct unique output filenames
    size_t sz = snprintf(NULL, 0, "%s/oclgrind_%lX.XX", tmpdir, m_uid) + 1;
    char *tempCL = new char[sz];
    char *tempIR = new char[sz];
    char *tempBC = new char[sz];
    sprintf(tempCL, "%s/oclgrind_%lX.cl", tmpdir, m_uid);
    sprintf(tempIR, "%s/oclgrind_%lX.ll", tmpdir, m_uid);
    sprintf(tempBC, "%s/oclgrind_%lX.bc", tmpdir, m_uid);

    // Dump source
    ofstream cl;
    cl.open(tempCL);
    cl << m_source;
    cl.close();

    if (m_buildStatus == CL_BUILD_SUCCESS)
    {
      // Dump IR
      string err;
      llvm::raw_fd_ostream ir(tempIR, err);
      llvm::AssemblyAnnotationWriter asmWriter;
      m_module->print(ir, &asmWriter);
      ir.close();

      // Dump bitcode
      llvm::raw_fd_ostream bc(tempBC, err);
      llvm::WriteBitcodeToFile(m_module, bc);
      bc.close();
    }

    delete[] tempCL;
    delete[] tempIR;
    delete[] tempBC;
  }

  return m_buildStatus == CL_BUILD_SUCCESS;
}

Program* Program::createFromBitcode(const unsigned char *bitcode,
                                    size_t length)
{
  // Load bitcode from file
  llvm::MemoryBuffer *buffer;
  llvm::StringRef data((const char*)bitcode, length);
  buffer = llvm::MemoryBuffer::getMemBuffer(data, "", false);
  if (!buffer)
  {
    return NULL;
  }

  // Parse bitcode into IR module
  llvm::LLVMContext& context = llvm::getGlobalContext();
  llvm::Module *module = ParseBitcodeFile(buffer, context);
  if (!module)
  {
    return NULL;
  }

  return new Program(module);
}

Program* Program::createFromBitcodeFile(const string filename)
{
  // Load bitcode from file
  llvm::OwningPtr<llvm::MemoryBuffer> buffer;
  if (llvm::MemoryBuffer::getFile(filename, buffer))
  {
    return NULL;
  }

  // Parse bitcode into IR module
  llvm::LLVMContext& context = llvm::getGlobalContext();
  llvm::Module *module = ParseBitcodeFile(buffer.get(), context);
  if (!module)
  {
    return NULL;
  }

  return new Program(module);
}

Program* Program::createFromPrograms(list<const Program*> programs)
{
  llvm::LLVMContext& context = llvm::getGlobalContext();
  llvm::Module *module = new llvm::Module("oclgrind_linked", context);
  llvm::Linker linker("oclgrind", module);

  // Link modules
  list<const Program*>::iterator itr;
  for (itr = programs.begin(); itr != programs.end(); itr++)
  {
    if (linker.LinkInModule(CloneModule((*itr)->m_module)))
    {
      return NULL;
    }
  }

  return new Program(linker.releaseModule());
}

Kernel* Program::createKernel(const string name)
{
  // Iterate over functions in module to find kernel
  llvm::Function *function = NULL;
  llvm::Module::iterator funcItr;
  for(funcItr = m_module->begin(); funcItr != m_module->end(); funcItr++)
  {
    // Check kernel name
    if (funcItr->getName().str() != name)
      continue;

    function = funcItr;
    break;
  }
  if (function == NULL)
  {
    return NULL;
  }

  // Assign identifiers to unnamed temporaries
  llvm::FunctionPass *instNamer = llvm::createInstructionNamerPass();
  instNamer->runOnFunction(*((llvm::Function*)function));
  delete instNamer;

  try
  {
    return new Kernel(*this, function, m_module);
  }
  catch (FatalError& err)
  {
    cerr << endl << "OCLGRIND FATAL ERROR "
         << "(" << err.getFile() << ":" << err.getLine() << ")"
         << endl << err.what()
         << endl << "When creating kernel '" << name << "'"
         << endl;
    return NULL;
  }
}

unsigned char* Program::getBinary() const
{
  if (!m_module)
  {
    return NULL;
  }

  std::string str;
  llvm::raw_string_ostream stream(str);
  llvm::WriteBitcodeToFile(m_module, stream);
  stream.str();
  unsigned char *bitcode = new unsigned char[str.length()];
  memcpy(bitcode, str.c_str(), str.length());
  return bitcode;
}

size_t Program::getBinarySize() const
{
  if (!m_module)
  {
    return 0;
  }

  std::string str;
  llvm::raw_string_ostream stream(str);
  llvm::WriteBitcodeToFile(m_module, stream);
  stream.str();
  return str.length();
}

const string& Program::getBuildLog() const
{
  return m_buildLog;
}

const string& Program::getBuildOptions() const
{
  return m_buildOptions;
}

unsigned int Program::getBuildStatus() const
{
  return m_buildStatus;
}

unsigned long Program::generateUID() const
{
  srand(now());
  return rand();
}

list<string> Program::getKernelNames() const
{
  list<string> names;

  // Iterate over functions in module to find kernels
  unsigned int num = 0;
  llvm::Function *function = NULL;
  llvm::Module::iterator funcItr;
  for(funcItr = m_module->begin(); funcItr != m_module->end(); funcItr++)
  {
    if (funcItr->getCallingConv() == llvm::CallingConv::SPIR_KERNEL)
    {
      names.push_back(funcItr->getName().str());
    }
  }

  return names;
}

unsigned int Program::getNumKernels() const
{
  assert(m_module != NULL);

  // Iterate over functions in module to find kernels
  unsigned int num = 0;
  llvm::Function *function = NULL;
  llvm::Module::iterator funcItr;
  for(funcItr = m_module->begin(); funcItr != m_module->end(); funcItr++)
  {
    if (funcItr->getCallingConv() == llvm::CallingConv::SPIR_KERNEL)
    {
      num++;
    }
  }

  return num;
}

const string& Program::getSource() const
{
  return m_source;
}

unsigned long Program::getUID() const
{
  return m_uid;
}
<|endoftext|>


<commit_before>// Filename: 	ql.cpp
// Author: 		Christopher Goes
// Course: 		CS 404 Machine Learning and Data Mining
// Semester: 	Spring 2016
// Description:	Assignment 6: Q-learning Mountain Car
// Github:		https://github.com/GhostofGoes/cgoes-cs404

#include <iostream>
#include <cmath>
#include "mat.h"

using namespace std;

#define DEBUG 0

// Reward: +1 at goal, -1 not at goal
// action(t) = 1 forward, action(t) = 0 coast, action(t) = -1 reverse
// bound enforces −1.2 ≤ xt+1 ≤ 0.8 and −0.07 ≤ vt+1 ≤ 0.07

double v( double currVel, double action, double currPos ); 	// vt+1 = bound(vt + 0.001at − 0.0025 cos(3xt))
double x( double currPos, double newVel ); 					// xt+1 = bound(xt + vt+1)
double clampX( double x );
double clampY( double y );

int main() {

	int goal = 0.8;		// Where we wan to be at the end of the insanity
	int numRows = 15; 	// velocity: 	steps of 0.01
	int numCols = 41; 	// position: 	steps of 0.05
	Matrix a[3];		// actions:		forward = 1, coast = 0, reverse = -1

	double vel = 0.0;	// velocity: 	steps of 0.01
	double pos = 0.0;	// position: 	steps of 0.05

	// The third dimension: actions. Thanks matt.
	a[0] = new Matrix(numRows, numCols, "reverse");
	a[1] = new Matrix(numRows, numCols, "coast");
	a[2] = new Matrix(numRows, numCols, "forward");

	for( Matrix &mat : a ) // Initialize Q-matricies to -1, 0, or 1
		mat.randInt(-1, 1);

	// Output: 3 Q-matricies to "run a mountain car"
	for( Matrix &mat : a )
		mat.write();

	return(0);
}

// vt+1 = bound(vt + 0.001at − 0.0025 cos(3xt))
double v( double currVel, double action, double currPos )
{
	double newVel = currVel;
	newVel += 0.001 * action;
	newVel -= 0.0025 * cos(3.0 * currPos);
	return clampY(newVel);
}

// xt+1 = bound(xt + vt+1)
double x( double currPos, double newVel )
{
	return clampX(currPos + newVel);
}

// −1.2 ≤ xt+1 ≤ 0.8
double clampX( double x )
{
	return x > 0.8 ? 0.8 : x < -1.2 ? -1.2 : x;
}

// −0.07 ≤ vt+1 ≤ 0.07
double clampY( double y )
{
	return y > 0.07 ? 0.07 : y < -0.07 ? -0.07 : y;
}<commit_msg>now there is Q and R lol<commit_after>// Filename: 	ql.cpp
// Author: 		Christopher Goes
// Course: 		CS 404 Machine Learning and Data Mining
// Semester: 	Spring 2016
// Description:	Assignment 6: Q-learning Mountain Car
// Github:		https://github.com/GhostofGoes/cgoes-cs404

#include <iostream>
#include <cmath>
#include "mat.h"

using namespace std;

#define DEBUG 0

// Reward: +1 at goal, -1 not at goal
// action(t) = 1 forward, action(t) = 0 coast, action(t) = -1 reverse
// bound enforces −1.2 ≤ xt+1 ≤ 0.8 and −0.07 ≤ vt+1 ≤ 0.07

int next( double pos, double vel, double action );
double v( double currVel, double action, double currPos ); 	// vt+1 = bound(vt + 0.001at − 0.0025 cos(3xt))
double x( double currPos, double newVel ); 					// xt+1 = bound(xt + vt+1)
double clampX( double x );
double clampY( double y );
Matrix r[3]; // reward matrix that has our "environment" state
Matrix q[3]; // path matrix

int main() {

	int numEpisodes = 0;
	int goal = 0.8;		// Where we want to be at the end of this insanity
	int numRows = 15; 	// velocity: 	steps of 0.01
	int numCols = 41; 	// position: 	steps of 0.05

	double currVel = 0.0, currPos = 0.0; 	// current state
	double newVel = 0.0, newPos = 0.0;		// new state
	double action = 0; 	// actions:	forward = 1, coast = 0, reverse = -1

	r[0] = new Matrix(numRows, numCols, "reverse");
	r[1] = new Matrix(numRows, numCols, "coast");
	r[2] = new Matrix(numRows, numCols, "forward");
	for( Matrix &mat : r ) // Initialize state to -1, 0, or 1
		mat.randInt(-1, 1);

	q[0] = new Matrix(numRows, numCols, "reverse");
	q[1] = new Matrix(numRows, numCols, "coast");
	q[2] = new Matrix(numRows, numCols, "forward");
	for( Matrix &mat : q )
		mat.constant(0.0); // zero out path matrix

	// Output: 3 Q-matricies to "run a mountain car"
	for( Matrix &mat : q )
		mat.write();

	return(0);
}

int next( double pos, double vel, int action )
{

}

// vt+1 = bound(vt + 0.001at − 0.0025 cos(3xt))
double v( double currVel, double action, double currPos )
{
	double newVel = currVel;
	newVel += 0.001 * action;
	newVel -= 0.0025 * cos(3.0 * currPos);
	return clampY(newVel);
}

// xt+1 = bound(xt + vt+1)
double x( double currPos, double newVel )
{
	return clampX(currPos + newVel);
}

// −1.2 ≤ xt+1 ≤ 0.8
double clampX( double x )
{
	return x > 0.8 ? 0.8 : x < -1.2 ? -1.2 : x;
}

// −0.07 ≤ vt+1 ≤ 0.07
double clampY( double y )
{
	return y > 0.07 ? 0.07 : y < -0.07 ? -0.07 : y;
}<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkRegularPolygonSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkRegularPolygonSource.h"

#include "vtkCellArray.h"
#include "vtkDoubleArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkObjectFactory.h"
#include "vtkMath.h"

vtkCxxRevisionMacro(vtkRegularPolygonSource, "1.1");
vtkStandardNewMacro(vtkRegularPolygonSource);

vtkRegularPolygonSource::vtkRegularPolygonSource()
{
  this->NumberOfSides = 6;
  this->Center[0] = 0.0; this->Center[1] = 0.0; this->Center[2] = 0.0;
  this->Normal[0] = 0.0; this->Normal[1] = 0.0; this->Normal[2] = 1.0;
  this->Radius = 0.5;
  this->GeneratePolygon = 1;
  this->GeneratePolyline = 1;

  this->SetNumberOfInputPorts(0);
}

int vtkRegularPolygonSource::RequestInformation(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  // get the info object
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(),-1);

  return 1;
}

int vtkRegularPolygonSource::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  // Get the info object
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // Get the output
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // We only produce one piece
  if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0)
    {
    return 1;
    }

  double x[3], r[3];
  int i, j, numPts=this->NumberOfSides;
  vtkPoints *newPoints;
  vtkCellArray *newPoly;
  vtkCellArray *newLine;

  // Prepare to produce the output; create the connectivity array(s)
  newPoints = vtkPoints::New();
  newPoints->Allocate(numPts);

  if ( this->GeneratePolyline )
    {
    newLine = vtkCellArray::New();
    newLine->Allocate(newLine->EstimateSize(1,numPts));
    newLine->InsertNextCell(numPts+1);
    for (i=0; i<numPts; i++)
      {
      newLine->InsertCellPoint(i);
      }
    newLine->InsertCellPoint(0); //close the polyline
    output->SetLines(newLine);
    newLine->Delete();
    }

  if ( this->GeneratePolygon )
    {
    newPoly = vtkCellArray::New();
    newPoly->Allocate(newPoly->EstimateSize(1,numPts));
    newPoly->InsertNextCell(numPts);
    for (i=0; i<numPts; i++)
      {
      newPoly->InsertCellPoint(i);
      }
    output->SetPolys(newPoly);
    newPoly->Delete();
    }

  // Produce a unit vector in the plane of the polygon (i.e., perpendicular
  // to the normal)
  double n[3], axis[3], p[3];

  // Make sure the polygon normal is a unit vector
  n[0] = this->Normal[0];
  n[1] = this->Normal[1];
  n[2] = this->Normal[2];
  if ( vtkMath::Normalize(n) == 0.0 )
    {
    n[0] = 0.0;
    n[1] = 0.0;
    n[2] = 1.0;
    }

  // Cross with unit axis vectors and eventually find vector in the polygon plane
  int foundPlaneVector = 0;
  axis[0] = 1.0;
  axis[1] = 0.0;
  axis[2] = 0.0;
  vtkMath::Cross(n,axis,p);
  if ( vtkMath::Normalize(p) > 1.0E-3 )
    {
    foundPlaneVector = 1;
    }
  if ( ! foundPlaneVector )
    {
    axis[0] = 0.0;
    axis[1] = 1.0;
    axis[2] = 0.0;
    vtkMath::Cross(n,axis,p);
    if ( vtkMath::Normalize(p) > 1.0E-3 )
      {
      foundPlaneVector = 1;
      }
    }
  if ( ! foundPlaneVector )
    {
    axis[0] = 0.0;
    axis[1] = 0.0;
    axis[2] = 1.0;
    vtkMath::Cross(n,axis,p);
    vtkMath::Normalize(p);
    }

  // Now run around normal vector to produce polygon points.
  double theta = 2.0 * vtkMath::DoublePi() / numPts;
  for (j=0; j<numPts; j++)
    {
    for (i=0; i<3; i++)
      {
      r[i] = p[i]*cos((double)j*theta) + n[i]*sin((double)j*theta);
      x[i] = this->Center[i] + this->Radius * r[i];
      }
    newPoints->InsertNextPoint(x);
    }

  output->SetPoints(newPoints);
  newPoints->Delete();

  return 1;
}

void vtkRegularPolygonSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Number of Sides: " << this->NumberOfSides << "\n";

  os << indent << "Center: (" << this->Center[0] << ", "
                              << this->Center[1] << ", "
                              << this->Center[2] << ")\n";

  os << indent << "Normal: (" << this->Normal[0] << ", "
                              << this->Normal[1] << ", "
                              << this->Normal[2] << ")\n";

  os << indent << "Radius: " << this->Radius << "\n";

  os << indent << "Generate Polygon: " << (this->GeneratePolygon ? "On\n" : "Off\n");

  os << indent << "Generate Polyline: " << (this->GeneratePolyline ? "On\n" : "Off\n");

}
<commit_msg>ENH:Better generation of polygon points<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkRegularPolygonSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkRegularPolygonSource.h"

#include "vtkCellArray.h"
#include "vtkDoubleArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkObjectFactory.h"
#include "vtkMath.h"

vtkCxxRevisionMacro(vtkRegularPolygonSource, "1.2");
vtkStandardNewMacro(vtkRegularPolygonSource);

vtkRegularPolygonSource::vtkRegularPolygonSource()
{
  this->NumberOfSides = 6;
  this->Center[0] = 0.0; this->Center[1] = 0.0; this->Center[2] = 0.0;
  this->Normal[0] = 0.0; this->Normal[1] = 0.0; this->Normal[2] = 1.0;
  this->Radius = 0.5;
  this->GeneratePolygon = 1;
  this->GeneratePolyline = 1;

  this->SetNumberOfInputPorts(0);
}

int vtkRegularPolygonSource::RequestInformation(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  // get the info object
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(),-1);

  return 1;
}

int vtkRegularPolygonSource::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  // Get the info object
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // Get the output
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // We only produce one piece
  if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0)
    {
    return 1;
    }

  double x[3], r[3];
  int i, j, numPts=this->NumberOfSides;
  vtkPoints *newPoints;
  vtkCellArray *newPoly;
  vtkCellArray *newLine;

  // Prepare to produce the output; create the connectivity array(s)
  newPoints = vtkPoints::New();
  newPoints->Allocate(numPts);

  if ( this->GeneratePolyline )
    {
    newLine = vtkCellArray::New();
    newLine->Allocate(newLine->EstimateSize(1,numPts));
    newLine->InsertNextCell(numPts+1);
    for (i=0; i<numPts; i++)
      {
      newLine->InsertCellPoint(i);
      }
    newLine->InsertCellPoint(0); //close the polyline
    output->SetLines(newLine);
    newLine->Delete();
    }

  if ( this->GeneratePolygon )
    {
    newPoly = vtkCellArray::New();
    newPoly->Allocate(newPoly->EstimateSize(1,numPts));
    newPoly->InsertNextCell(numPts);
    for (i=0; i<numPts; i++)
      {
      newPoly->InsertCellPoint(i);
      }
    output->SetPolys(newPoly);
    newPoly->Delete();
    }

  // Produce a unit vector in the plane of the polygon (i.e., perpendicular
  // to the normal)
  double n[3], axis[3], px[3], py[3];

  // Make sure the polygon normal is a unit vector
  n[0] = this->Normal[0];
  n[1] = this->Normal[1];
  n[2] = this->Normal[2];
  if ( vtkMath::Normalize(n) == 0.0 )
    {
    n[0] = 0.0;
    n[1] = 0.0;
    n[2] = 1.0;
    }

  // Cross with unit axis vectors and eventually find vector in the polygon plane
  int foundPlaneVector = 0;
  axis[0] = 1.0;
  axis[1] = 0.0;
  axis[2] = 0.0;
  vtkMath::Cross(n,axis,px);
  if ( vtkMath::Normalize(px) > 1.0E-3 )
    {
    foundPlaneVector = 1;
    }
  if ( ! foundPlaneVector )
    {
    axis[0] = 0.0;
    axis[1] = 1.0;
    axis[2] = 0.0;
    vtkMath::Cross(n,axis,px);
    if ( vtkMath::Normalize(px) > 1.0E-3 )
      {
      foundPlaneVector = 1;
      }
    }
  if ( ! foundPlaneVector )
    {
    axis[0] = 0.0;
    axis[1] = 0.0;
    axis[2] = 1.0;
    vtkMath::Cross(n,axis,px);
    vtkMath::Normalize(px);
    }
  vtkMath::Cross(px,n,py); //created two orthogonal axes in the polygon plane, px & py

  // Now run around normal vector to produce polygon points.
  double theta = 2.0 * vtkMath::DoublePi() / numPts;
  for (j=0; j<numPts; j++)
    {
    for (i=0; i<3; i++)
      {
      r[i] = px[i]*cos((double)j*theta) + py[i]*sin((double)j*theta);
      x[i] = this->Center[i] + this->Radius * r[i];
      }
    newPoints->InsertNextPoint(x);
    }

  output->SetPoints(newPoints);
  newPoints->Delete();

  return 1;
}

void vtkRegularPolygonSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Number of Sides: " << this->NumberOfSides << "\n";

  os << indent << "Center: (" << this->Center[0] << ", "
                              << this->Center[1] << ", "
                              << this->Center[2] << ")\n";

  os << indent << "Normal: (" << this->Normal[0] << ", "
                              << this->Normal[1] << ", "
                              << this->Normal[2] << ")\n";

  os << indent << "Radius: " << this->Radius << "\n";

  os << indent << "Generate Polygon: " << (this->GeneratePolygon ? "On\n" : "Off\n");

  os << indent << "Generate Polyline: " << (this->GeneratePolyline ? "On\n" : "Off\n");

}
<|endoftext|>


<commit_before>// Filename: asyncTaskBase.cxx
// Created by:  drose (09Feb10)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "asyncTaskBase.h"
#include "thread.h"
#include "atomicAdjust.h"

TypeHandle AsyncTaskBase::_type_handle;

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::Constructor
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
AsyncTaskBase::
AsyncTaskBase() {
}

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::Destructor
//       Access: Published, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
AsyncTaskBase::
~AsyncTaskBase() {
}

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::record_task
//       Access: Protected
//  Description: Indicates that this task is now the current task
//               running on the indicated thread, presumably the
//               current thread.
////////////////////////////////////////////////////////////////////
void AsyncTaskBase::
record_task(Thread *current_thread) {
  nassertv(current_thread->_current_task == NULL);

  void *result = AtomicAdjust::compare_and_exchange_ptr
    ((void * TVOLATILE &)current_thread->_current_task,
     (void *)NULL, (void *)this);

  // If the return value is other than NULL, someone else must have
  // assigned the task first, in another thread.  That shouldn't be
  // possible.
  nassertv(result == NULL);
  nassertv(current_thread->_current_task == this);
}

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::clear_task
//       Access: Protected
//  Description: Indicates that this task is no longer running on the
//               indicated thread.
////////////////////////////////////////////////////////////////////
void AsyncTaskBase::
clear_task(Thread *current_thread) {
  nassertv(current_thread->_current_task == this);

  void *result = AtomicAdjust::compare_and_exchange_ptr
    ((void * TVOLATILE &)current_thread->_current_task,
     (void *)this, (void *)NULL);

  // If the return value is other than this, someone else must have
  // assigned the task first, in another thread.  That shouldn't be
  // possible.
  nassertv(result == this);
  nassertv(current_thread->_current_task == NULL);
}
<commit_msg>protect against gcc compiler bugs in general<commit_after>// Filename: asyncTaskBase.cxx
// Created by:  drose (09Feb10)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "asyncTaskBase.h"
#include "thread.h"
#include "atomicAdjust.h"

TypeHandle AsyncTaskBase::_type_handle;

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::Constructor
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
AsyncTaskBase::
AsyncTaskBase() {
}

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::Destructor
//       Access: Published, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
AsyncTaskBase::
~AsyncTaskBase() {
}

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::record_task
//       Access: Protected
//  Description: Indicates that this task is now the current task
//               running on the indicated thread, presumably the
//               current thread.
////////////////////////////////////////////////////////////////////
void AsyncTaskBase::
record_task(Thread *current_thread) {
  nassertv(current_thread->_current_task == NULL);

  void *result = AtomicAdjust::compare_and_exchange_ptr
    ((void * TVOLATILE &)current_thread->_current_task,
     (void *)NULL, (void *)this);

  // If the return value is other than NULL, someone else must have
  // assigned the task first, in another thread.  That shouldn't be
  // possible.

  // But different versions of gcc appear to have problems compiling these
  // assertions correctly.
#ifndef __GNUC__
  nassertv(result == NULL);
  nassertv(current_thread->_current_task == this);
#endif  // __GNUC__
}

////////////////////////////////////////////////////////////////////
//     Function: AsyncTaskBase::clear_task
//       Access: Protected
//  Description: Indicates that this task is no longer running on the
//               indicated thread.
////////////////////////////////////////////////////////////////////
void AsyncTaskBase::
clear_task(Thread *current_thread) {
  nassertv(current_thread->_current_task == this);

  void *result = AtomicAdjust::compare_and_exchange_ptr
    ((void * TVOLATILE &)current_thread->_current_task,
     (void *)this, (void *)NULL);

  // If the return value is other than this, someone else must have
  // assigned the task first, in another thread.  That shouldn't be
  // possible.

  // But different versions of gcc appear to have problems compiling these
  // assertions correctly.
#ifndef __GNUC__
  nassertv(result == this);
  nassertv(current_thread->_current_task == NULL);
#endif  // __GNUC__
}
<|endoftext|>


<commit_before>// clang-format off
{{#global}}
#include <SoftwareSerial.h>
{{/global}}
// clang-format on

class SoftwareUart : public Uart {
private:
    SoftwareSerial _serial;
    uint8_t _rx;
    uint8_t _tx;

public:
    SoftwareUart(uint8_t rx, uint8_t tx, long baud = 9600)
        : Uart(baud)
        , _serial(rx, tx) {
        _rx = rx;
        _tx = tx;
    }

    void begin();
    void end();
    void flush();

    bool available() {
        return (bool)_serial.available();
    }

    bool writeByte(uint8_t byte) {
        return (bool)_serial.write(byte);
    }

    bool readByte(uint8_t* out) {
        int data = _serial.read();
        if (data == -1)
            return false;
        *out = data;
        return true;
    }

    uint8_t getRX() {
        return _rx;
    }

    uint8_t getTX() {
        return _tx;
    }

    SoftwareSerial* toSoftwareSerial() {
        return &_serial;
    }
};

void SoftwareUart::begin() {
    _started = true;
    _serial.begin(getBaudRate());
};
void SoftwareUart::end() {
    _started = false;
    _serial.end();
};
void SoftwareUart::flush() {
    _serial.flush();
}

struct State {
    uint8_t mem[sizeof(SoftwareUart)];
    SoftwareUart* uart;
};

// clang-format off
{{ GENERATED_CODE }}
// clang-format on

void evaluate(Context ctx) {
    auto state = getState(ctx);

    if (isSettingUp()) {
        uint8_t rx = getValue<input_RX>(ctx);
        uint8_t tx = getValue<input_TX>(ctx);
        long baud = (long)getValue<input_BAUD>(ctx);
        state->uart = new (state->mem) SoftwareUart(rx, tx, baud);
        emitValue<output_UART>(ctx, state->uart);
    }

    if (isInputDirty<input_INIT>(ctx)) {
        state->uart->begin();
        emitValue<output_DONE>(ctx, 1);
    }
}
<commit_msg>tweak(stdlib): explicitly convert int to uint8_t when reading byte in xod/uart/soft-uart<commit_after>// clang-format off
{{#global}}
#include <SoftwareSerial.h>
{{/global}}
// clang-format on

class SoftwareUart : public Uart {
private:
    SoftwareSerial _serial;
    uint8_t _rx;
    uint8_t _tx;

public:
    SoftwareUart(uint8_t rx, uint8_t tx, long baud = 9600)
        : Uart(baud)
        , _serial(rx, tx) {
        _rx = rx;
        _tx = tx;
    }

    void begin();
    void end();
    void flush();

    bool available() {
        return (bool)_serial.available();
    }

    bool writeByte(uint8_t byte) {
        return (bool)_serial.write(byte);
    }

    bool readByte(uint8_t* out) {
        int data = _serial.read();
        if (data == -1)
            return false;
        *out = (uint8_t)data;
        return true;
    }

    uint8_t getRX() {
        return _rx;
    }

    uint8_t getTX() {
        return _tx;
    }

    SoftwareSerial* toSoftwareSerial() {
        return &_serial;
    }
};

void SoftwareUart::begin() {
    _started = true;
    _serial.begin(getBaudRate());
};
void SoftwareUart::end() {
    _started = false;
    _serial.end();
};
void SoftwareUart::flush() {
    _serial.flush();
}

struct State {
    uint8_t mem[sizeof(SoftwareUart)];
    SoftwareUart* uart;
};

// clang-format off
{{ GENERATED_CODE }}
// clang-format on

void evaluate(Context ctx) {
    auto state = getState(ctx);

    if (isSettingUp()) {
        uint8_t rx = getValue<input_RX>(ctx);
        uint8_t tx = getValue<input_TX>(ctx);
        long baud = (long)getValue<input_BAUD>(ctx);
        state->uart = new (state->mem) SoftwareUart(rx, tx, baud);
        emitValue<output_UART>(ctx, state->uart);
    }

    if (isInputDirty<input_INIT>(ctx)) {
        state->uart->begin();
        emitValue<output_DONE>(ctx, 1);
    }
}
<|endoftext|>


<commit_before>#include "openmc/tallies/trigger.h"

#include <cmath>
#include <sstream>
#include <utility> // for std::pair

#include "openmc/capi.h"
#include "openmc/constants.h"
#include "openmc/error.h"
#include "openmc/reaction.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/tallies/tally.h"

namespace openmc {

//==============================================================================
// Global variable definitions
//==============================================================================

namespace settings {
  KTrigger keff_trigger;
}

//==============================================================================
// Non-member functions
//==============================================================================

std::pair<double, double>
get_tally_uncertainty(int i_tally, int score_index, int filter_index)
{
  const auto& tally {model::tallies[i_tally]};

  auto sum = tally->results_(filter_index, score_index, RESULT_SUM);
  auto sum_sq = tally->results_(filter_index, score_index, RESULT_SUM_SQ);

  int n = tally->n_realizations_;
  auto mean = sum / n;
  double std_dev = std::sqrt((sum_sq/n - mean*mean) / (n-1));
  double rel_err = (mean != 0.) ? std_dev / std::abs(mean) : 0.;

  return {std_dev, rel_err};
}

//! Find the limiting limiting tally trigger.
//
//! param[out] ratio The uncertainty/threshold ratio for the most limiting
//!   tally trigger
//! param[out] tally_id The ID number of the most limiting tally
//! param[out] score The most limiting tally score bin

void
check_tally_triggers(double& ratio, int& tally_id, int& score)
{
  ratio = 0.;
  for (auto i_tally = 0; i_tally < model::tallies.size(); ++i_tally) {
    const Tally& t {*model::tallies[i_tally]};

    // Ignore tallies with less than two realizations.
    if (t.n_realizations_ < 2) continue;

    for (const auto& trigger : t.triggers_) {
      const auto& results = t.results_;
      for (auto filter_index = 0; filter_index < results.shape()[0];
           ++filter_index) {
        for (auto score_index = 0; score_index < results.shape()[1];
             ++score_index) {
          // Compute the tally uncertainty metrics.
          auto uncert_pair = get_tally_uncertainty(i_tally, score_index,
            filter_index);
          double std_dev = uncert_pair.first;
          double rel_err = uncert_pair.second;

          // Pick out the relevant uncertainty metric for this trigger.
          double uncertainty;
          switch (trigger.metric) {
            case TriggerMetric::variance:
              uncertainty = std_dev * std_dev;
              break;
            case TriggerMetric::standard_deviation:
              uncertainty = std_dev;
              break;
            case TriggerMetric::relative_error:
              uncertainty = rel_err;
              break;
            case TriggerMetric::not_active:
              uncertainty = 0.0;
              break;
          }

          // Compute the uncertainty / threshold ratio.
          double this_ratio = uncertainty / trigger.threshold;
          if (trigger.metric == TriggerMetric::variance) {
            this_ratio = std::sqrt(ratio);
          }

          // If this is the most uncertain value, set the output variables.
          if (this_ratio > ratio) {
            ratio = this_ratio;
            score = t.scores_[trigger.score_index];
            tally_id = t.id_;
          }
        }
      }
    }
  }
}

//! Compute the uncertainty/threshold ratio for the eigenvalue trigger.

double
check_keff_trigger()
{
  if (settings::run_mode != RUN_MODE_EIGENVALUE) return 0.;

  double k_combined[2];
  openmc_get_keff(k_combined);

  double uncertainty = 0.;
  switch (settings::keff_trigger.metric) {
  case TriggerMetric::variance:
    uncertainty = k_combined[1] * k_combined[1];
    break;
  case TriggerMetric::standard_deviation:
    uncertainty = k_combined[1];
    break;
  case TriggerMetric::relative_error:
    uncertainty = k_combined[1] / k_combined[0];
    break;
  case TriggerMetric::not_active:
    break;
  }

  double ratio = uncertainty / settings::keff_trigger.threshold;
  if (settings::keff_trigger.metric == TriggerMetric::variance)
    ratio = std::sqrt(ratio);
  return ratio;
}

//! See if tally and eigenvalue uncertainties are under trigger thresholds.

void
check_triggers()
{
  // Make some aliases.
  const auto current_batch {simulation::current_batch};
  const auto n_batches {settings::n_batches};
  const auto interval {settings::trigger_batch_interval};

  // See if the current batch is one for which the triggers must be checked.
  if (!settings::trigger_on) return;
  if (current_batch < n_batches) return;
  if (((current_batch - n_batches) % interval) != 0) return;

  // Check the eigenvalue and tally triggers.
  double keff_ratio = check_keff_trigger();
  double tally_ratio;
  int tally_id, score;
  check_tally_triggers(tally_ratio, tally_id, score);

  // If all the triggers are satisfied, alert the user and return.
  if (std::max(keff_ratio, tally_ratio) <= 1.) {
    simulation::satisfy_triggers = true;
    write_message("Triggers satisfied for batch "
      + std::to_string(current_batch), 7);
    return;
  }

  // At least one trigger is unsatisfied.  Let the user know which one.
  simulation::satisfy_triggers = false;
  std::stringstream msg;
  msg << "Triggers unsatisfied, max unc./thresh. is ";
  if (keff_ratio >= tally_ratio) {
    msg << keff_ratio << " for eigenvalue";
  } else {
    msg << tally_ratio << " for " << reaction_name(score) << " in tally "
        << tally_id;
  }
  write_message(msg, 7);

  // Estimate batches til triggers are satisfied.
  if (settings::trigger_predict) {
    // This calculation assumes tally variance is proportional to 1/N where N is
    // the number of batches.
    auto max_ratio = std::max(keff_ratio, tally_ratio);
    auto n_active = current_batch - settings::n_inactive;
    auto n_pred_batches = static_cast<int>(n_active * max_ratio * max_ratio)
      + settings::n_inactive + 1;

    std::stringstream msg;
    msg << "The estimated number of batches is " << n_pred_batches;
    if (n_pred_batches > settings::n_max_batches) {
      msg << " --- greater than max batches";
      warning(msg);
    } else {
      write_message(msg, 7);
    }
  }
}

} // namespace openmc
<commit_msg>stop division by zero in keff trigger if no trigger given<commit_after>#include "openmc/tallies/trigger.h"

#include <cmath>
#include <sstream>
#include <utility> // for std::pair

#include "openmc/capi.h"
#include "openmc/constants.h"
#include "openmc/error.h"
#include "openmc/reaction.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/tallies/tally.h"

namespace openmc {

//==============================================================================
// Global variable definitions
//==============================================================================

namespace settings {
  KTrigger keff_trigger;
}

//==============================================================================
// Non-member functions
//==============================================================================

std::pair<double, double>
get_tally_uncertainty(int i_tally, int score_index, int filter_index)
{
  const auto& tally {model::tallies[i_tally]};

  auto sum = tally->results_(filter_index, score_index, RESULT_SUM);
  auto sum_sq = tally->results_(filter_index, score_index, RESULT_SUM_SQ);

  int n = tally->n_realizations_;
  auto mean = sum / n;
  double std_dev = std::sqrt((sum_sq/n - mean*mean) / (n-1));
  double rel_err = (mean != 0.) ? std_dev / std::abs(mean) : 0.;

  return {std_dev, rel_err};
}

//! Find the limiting limiting tally trigger.
//
//! param[out] ratio The uncertainty/threshold ratio for the most limiting
//!   tally trigger
//! param[out] tally_id The ID number of the most limiting tally
//! param[out] score The most limiting tally score bin

void
check_tally_triggers(double& ratio, int& tally_id, int& score)
{
  ratio = 0.;
  for (auto i_tally = 0; i_tally < model::tallies.size(); ++i_tally) {
    const Tally& t {*model::tallies[i_tally]};

    // Ignore tallies with less than two realizations.
    if (t.n_realizations_ < 2) continue;

    for (const auto& trigger : t.triggers_) {
      const auto& results = t.results_;
      for (auto filter_index = 0; filter_index < results.shape()[0];
           ++filter_index) {
        for (auto score_index = 0; score_index < results.shape()[1];
             ++score_index) {
          // Compute the tally uncertainty metrics.
          auto uncert_pair = get_tally_uncertainty(i_tally, score_index,
            filter_index);
          double std_dev = uncert_pair.first;
          double rel_err = uncert_pair.second;

          // Pick out the relevant uncertainty metric for this trigger.
          double uncertainty;
          switch (trigger.metric) {
            case TriggerMetric::variance:
              uncertainty = std_dev * std_dev;
              break;
            case TriggerMetric::standard_deviation:
              uncertainty = std_dev;
              break;
            case TriggerMetric::relative_error:
              uncertainty = rel_err;
              break;
            case TriggerMetric::not_active:
              uncertainty = 0.0;
              break;
          }

          // Compute the uncertainty / threshold ratio.
          double this_ratio = uncertainty / trigger.threshold;
          if (trigger.metric == TriggerMetric::variance) {
            this_ratio = std::sqrt(ratio);
          }

          // If this is the most uncertain value, set the output variables.
          if (this_ratio > ratio) {
            ratio = this_ratio;
            score = t.scores_[trigger.score_index];
            tally_id = t.id_;
          }
        }
      }
    }
  }
}

//! Compute the uncertainty/threshold ratio for the eigenvalue trigger.

double
check_keff_trigger()
{
  if (settings::run_mode != RUN_MODE_EIGENVALUE) return 0.0;

  double k_combined[2];
  openmc_get_keff(k_combined);

  double uncertainty = 0.;
  switch (settings::keff_trigger.metric) {
  case TriggerMetric::variance:
    uncertainty = k_combined[1] * k_combined[1];
    break;
  case TriggerMetric::standard_deviation:
    uncertainty = k_combined[1];
    break;
  case TriggerMetric::relative_error:
    uncertainty = k_combined[1] / k_combined[0];
    break;
  default:
    // If it's an unrecognized TriggerMetric or no keff trigger is on,
    // return 0 to stop division by zero where "ratio" is calculated.
    return 0.0;
  }

  double ratio = uncertainty / settings::keff_trigger.threshold;
  if (settings::keff_trigger.metric == TriggerMetric::variance)
    ratio = std::sqrt(ratio);
  return ratio;
}

//! See if tally and eigenvalue uncertainties are under trigger thresholds.

void
check_triggers()
{
  // Make some aliases.
  const auto current_batch {simulation::current_batch};
  const auto n_batches {settings::n_batches};
  const auto interval {settings::trigger_batch_interval};

  // See if the current batch is one for which the triggers must be checked.
  if (!settings::trigger_on) return;
  if (current_batch < n_batches) return;
  if (((current_batch - n_batches) % interval) != 0) return;

  // Check the eigenvalue and tally triggers.
  double keff_ratio = check_keff_trigger();
  double tally_ratio;
  int tally_id, score;
  check_tally_triggers(tally_ratio, tally_id, score);

  // If all the triggers are satisfied, alert the user and return.
  if (std::max(keff_ratio, tally_ratio) <= 1.) {
    simulation::satisfy_triggers = true;
    write_message("Triggers satisfied for batch "
      + std::to_string(current_batch), 7);
    return;
  }

  // At least one trigger is unsatisfied.  Let the user know which one.
  simulation::satisfy_triggers = false;
  std::stringstream msg;
  msg << "Triggers unsatisfied, max unc./thresh. is ";
  if (keff_ratio >= tally_ratio) {
    msg << keff_ratio << " for eigenvalue";
  } else {
    msg << tally_ratio << " for " << reaction_name(score) << " in tally "
        << tally_id;
  }
  write_message(msg, 7);

  // Estimate batches til triggers are satisfied.
  if (settings::trigger_predict) {
    // This calculation assumes tally variance is proportional to 1/N where N is
    // the number of batches.
    auto max_ratio = std::max(keff_ratio, tally_ratio);
    auto n_active = current_batch - settings::n_inactive;
    auto n_pred_batches = static_cast<int>(n_active * max_ratio * max_ratio)
      + settings::n_inactive + 1;

    std::stringstream msg;
    msg << "The estimated number of batches is " << n_pred_batches;
    if (n_pred_batches > settings::n_max_batches) {
      msg << " --- greater than max batches";
      warning(msg);
    } else {
      write_message(msg, 7);
    }
  }
}

} // namespace openmc
<|endoftext|>