<commit_before>#if defined(__unix__) || defined(__APPLE__)

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "Tools.h"
#include "Types.h"

namespace {

int RedirectOutput(const BotConfig &Agent, int SrcFD, const char *LogFile)
{
    int logFD = open(LogFile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (logFD < 0) {
        std::cerr << Agent.BotName +
            ": Failed to create a log file, error: " +
            strerror(errno) << std::endl;
            return logFD;
    }

    int ret = dup2(logFD, SrcFD);
    if (ret < 0) {
        std::cerr << Agent.BotName +
            ": Can't redirect output to a log file, error: " +
            strerror(errno) << std::endl;
        return ret;
    }

    close(logFD);
    return ret;
}

} // namespace

void StartBotProcess(const BotConfig &Agent, const std::string &CommandLine, unsigned long *ProcessId)
{
    pid_t pID = fork();

    if (pID < 0)
    {
        std::cerr << Agent.BotName + ": Can't fork the bot process, error: " +
            strerror(errno) << std::endl;
        return;
    }

    if (pID == 0) // child
    {
        int ret = chdir(Agent.RootPath.c_str());
        if (ret < 0) {
            std::cerr << Agent.BotName +
                ": Can't change working directory to " + Agent.RootPath +
                ", error: " + strerror(errno) << std::endl;
            exit(errno);
        }

        if (RedirectOutput(Agent, STDERR_FILENO, "stderr.log") < 0)
            exit(errno);

        if (Agent.Debug)
        {
            if (RedirectOutput(Agent, STDOUT_FILENO, "stdout.log") < 0)
                exit(errno);
        }
        else
            close(STDOUT_FILENO);

        close(STDIN_FILENO);

        std::vector<char*> unix_cmd;
        std::istringstream stream(CommandLine);
        std::istream_iterator<std::string> begin(stream), end;
        std::vector<std::string> tokens(begin, end);
        for (const auto& i : tokens)
            unix_cmd.push_back(const_cast<char*>(i.c_str()));

        // FIXME (alkurbatov): Unfortunately, the cmdline uses relative path.
        // This hack is needed because we have to change the working directory
        // before calling to exec.
        if (Agent.Type == BinaryCpp)
            unix_cmd[0] = const_cast<char*>(Agent.FileName.c_str());

        unix_cmd.push_back(NULL);

        // NOTE (alkurbatov): For the Python bots we need to search in the PATH
        // for the interpreter.
        if (Agent.Type == Python || Agent.Type == Wine || Agent.Type == Mono || Agent.Type == DotNetCore)
            ret = execvp(unix_cmd.front(), &unix_cmd.front());
        else
            ret = execv(unix_cmd.front(), &unix_cmd.front());

        if (ret < 0)
        {
            std::cerr << Agent.BotName + ": Failed to execute '" + CommandLine +
                "', error: " + strerror(errno) << std::endl;
            exit(errno);
        }

        exit(0);
    }

    // parent
    *ProcessId = pID;

    int exit_status = 0;
    int ret = waitpid(pID, &exit_status, 0);
    if (ret < 0) {
        std::cerr << Agent.BotName +
            ": Can't wait for the child process, error:" +
            strerror(errno) << std::endl;
    }
}

void StartExternalProcess(const std::string CommandLine)
{
	execve(CommandLine.c_str(), NULL, NULL);
}

void SleepFor(int seconds)
{
    sleep(seconds);
}

void KillSc2Process(unsigned long pid)
{
    int ret = kill(pid, SIGKILL);
    if (ret < 0)
    {
        std::cerr << std::string("Failed to send SIGKILL, error:") +
            strerror(errno) << std::endl;
    }
}

bool MoveReplayFile(const char* lpExistingFileName, const  char* lpNewFileName)
{
    int ret = rename(lpExistingFileName, lpNewFileName);
    if (ret < 0)
    {
        std::cerr << std::string("Failed to move a replay file, error:") +
            strerror(errno) << std::endl;
    }

    return ret == 0;
}

#endif<commit_msg>Fix to make java bots work with Linux<commit_after>#if defined(__unix__) || defined(__APPLE__)

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "Tools.h"
#include "Types.h"

namespace {

int RedirectOutput(const BotConfig &Agent, int SrcFD, const char *LogFile)
{
    int logFD = open(LogFile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (logFD < 0) {
        std::cerr << Agent.BotName +
            ": Failed to create a log file, error: " +
            strerror(errno) << std::endl;
            return logFD;
    }

    int ret = dup2(logFD, SrcFD);
    if (ret < 0) {
        std::cerr << Agent.BotName +
            ": Can't redirect output to a log file, error: " +
            strerror(errno) << std::endl;
        return ret;
    }

    close(logFD);
    return ret;
}

} // namespace

void StartBotProcess(const BotConfig &Agent, const std::string &CommandLine, unsigned long *ProcessId)
{
    pid_t pID = fork();

    if (pID < 0)
    {
        std::cerr << Agent.BotName + ": Can't fork the bot process, error: " +
            strerror(errno) << std::endl;
        return;
    }

    if (pID == 0) // child
    {
        int ret = chdir(Agent.RootPath.c_str());
        if (ret < 0) {
            std::cerr << Agent.BotName +
                ": Can't change working directory to " + Agent.RootPath +
                ", error: " + strerror(errno) << std::endl;
            exit(errno);
        }

        if (RedirectOutput(Agent, STDERR_FILENO, "stderr.log") < 0)
            exit(errno);

        if (Agent.Debug)
        {
            if (RedirectOutput(Agent, STDOUT_FILENO, "stdout.log") < 0)
                exit(errno);
        }
        else
            close(STDOUT_FILENO);

        close(STDIN_FILENO);

        std::vector<char*> unix_cmd;
        std::istringstream stream(CommandLine);
        std::istream_iterator<std::string> begin(stream), end;
        std::vector<std::string> tokens(begin, end);
        for (const auto& i : tokens)
            unix_cmd.push_back(const_cast<char*>(i.c_str()));

        // FIXME (alkurbatov): Unfortunately, the cmdline uses relative path.
        // This hack is needed because we have to change the working directory
        // before calling to exec.
        if (Agent.Type == BinaryCpp)
            unix_cmd[0] = const_cast<char*>(Agent.FileName.c_str());

        unix_cmd.push_back(NULL);

        // NOTE (alkurbatov): For the Python bots we need to search in the PATH
        // for the interpreter.
        if (Agent.Type == Python || Agent.Type == Wine || Agent.Type == Mono || Agent.Type == DotNetCore || Agent.Type == Java)
            ret = execvp(unix_cmd.front(), &unix_cmd.front());
        else
            ret = execv(unix_cmd.front(), &unix_cmd.front());

        if (ret < 0)
        {
            std::cerr << Agent.BotName + ": Failed to execute '" + CommandLine +
                "', error: " + strerror(errno) << std::endl;
            exit(errno);
        }

        exit(0);
    }

    // parent
    *ProcessId = pID;

    int exit_status = 0;
    int ret = waitpid(pID, &exit_status, 0);
    if (ret < 0) {
        std::cerr << Agent.BotName +
            ": Can't wait for the child process, error:" +
            strerror(errno) << std::endl;
    }
}

void StartExternalProcess(const std::string CommandLine)
{
	execve(CommandLine.c_str(), NULL, NULL);
}

void SleepFor(int seconds)
{
    sleep(seconds);
}

void KillSc2Process(unsigned long pid)
{
    int ret = kill(pid, SIGKILL);
    if (ret < 0)
    {
        std::cerr << std::string("Failed to send SIGKILL, error:") +
            strerror(errno) << std::endl;
    }
}

bool MoveReplayFile(const char* lpExistingFileName, const  char* lpNewFileName)
{
    int ret = rename(lpExistingFileName, lpNewFileName);
    if (ret < 0)
    {
        std::cerr << std::string("Failed to move a replay file, error:") +
            strerror(errno) << std::endl;
    }

    return ret == 0;
}

#endif<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_OBJECTFACTORY_HPP_
#define _QITYPE_OBJECTFACTORY_HPP_

#include <vector>

#include <boost/function.hpp>

#include <qitype/api.hpp>
#include <qitype/fwd.hpp>
#include <qitype/type.hpp>
#include <qitype/genericobjectbuilder.hpp>

namespace qi {

  QITYPE_API bool registerObjectFactory(const std::string& name, boost::function<qi::ObjectPtr (const std::string&)> factory);

  QITYPE_API qi::ObjectPtr createObject(const std::string& name);

  /// Get all factory names. Order is guaranteed to be the registration order
  QITYPE_API std::vector<std::string> listObjectFactories();

  /// Load a shared library and return the list of new available factory names.
  QITYPE_API std::vector<std::string> loadObject(const std::string& name, int flags = -1);
}

/// register \p func as factory for object named \p name
#define QI_REGISTER_OBJECT_FACTORY(name, func) \
  static bool BOOST_PP_CAT(_register_factory_ ,__LINE__) = ::qi::registerObjectFactory(name, func)

/// register \p name's default constructor as factory for \p name
#define QI_REGISTER_OBJECT_FACTORY_CONSTRUCTOR(name) \
  QI_REGISTER_OBJECT_FACTORY(#name, boost::bind(::qi::detail::constructObject<name>))

/** Register a factory on \p name that creates an object with a single method
  * \p func named \p funcName
  */
#define QI_REGISTER_OBJECT_FACTORY_METHOD(name, funcName, func) \
  QI_REGISTER_OBJECT_FACTORY(name, ::qi::detail::makeObjectFactory(funcName, func))

/** Register an object as a factory for an other object
 * @param name target class name
 *
 * Will crate a factory for generated object 'name + "Service"',
 * with a create() method
 * that returns a newly created instance of \p name.
 */
#define QI_REGISTER_OBJECT_FACTORY_BUILDER(name)                      \
  QI_REGISTER_OBJECT_FACTORY_METHOD(#name "Service", "create", ::qi::detail::constructObject<name>)

#endif  // _QITYPE_OBJECTFACTORY_HPP_
<commit_msg>Object factory: Replace __LINE__ by __COUNTER__.<commit_after>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_OBJECTFACTORY_HPP_
#define _QITYPE_OBJECTFACTORY_HPP_

#include <vector>

#include <boost/function.hpp>

#include <qitype/api.hpp>
#include <qitype/fwd.hpp>
#include <qitype/type.hpp>
#include <qitype/genericobjectbuilder.hpp>

namespace qi {

  QITYPE_API bool registerObjectFactory(const std::string& name, boost::function<qi::ObjectPtr (const std::string&)> factory);

  QITYPE_API qi::ObjectPtr createObject(const std::string& name);

  /// Get all factory names. Order is guaranteed to be the registration order
  QITYPE_API std::vector<std::string> listObjectFactories();

  /// Load a shared library and return the list of new available factory names.
  QITYPE_API std::vector<std::string> loadObject(const std::string& name, int flags = -1);
}

/// register \p func as factory for object named \p name
#define QI_REGISTER_OBJECT_FACTORY(name, func) \
  static bool BOOST_PP_CAT(_register_factory_ ,__COUNTER__) = ::qi::registerObjectFactory(name, func)

/// register \p name's default constructor as factory for \p name
#define QI_REGISTER_OBJECT_FACTORY_CONSTRUCTOR(name) \
  QI_REGISTER_OBJECT_FACTORY(#name, boost::bind(::qi::detail::constructObject<name>))

/** Register a factory on \p name that creates an object with a single method
  * \p func named \p funcName
  */
#define QI_REGISTER_OBJECT_FACTORY_METHOD(name, funcName, func) \
  QI_REGISTER_OBJECT_FACTORY(name, ::qi::detail::makeObjectFactory(funcName, func))

/** Register an object as a factory for an other object
 * @param name target class name
 *
 * Will crate a factory for generated object 'name + "Service"',
 * with a create() method
 * that returns a newly created instance of \p name.
 */
#define QI_REGISTER_OBJECT_FACTORY_BUILDER(name)                      \
  QI_REGISTER_OBJECT_FACTORY_METHOD(#name "Service", "create", ::qi::detail::constructObject<name>)

#endif  // _QITYPE_OBJECTFACTORY_HPP_
<|endoftext|>


<commit_before><commit_msg>Some failed experiments (commented out).<commit_after><|endoftext|>


<commit_before><commit_msg>Added some tasks to TODO list.<commit_after><|endoftext|>


<commit_before>#include "assign_bilinear_bases_dist.hxx"
#include "../../SDP.hxx"
#include "set_bases_blocks.hxx"

#include <boost/filesystem.hpp>

#include <iterator>

void read_blocks(const boost::filesystem::path &sdp_directory,
                 const El::Grid &grid, const Block_Info &block_info, SDP &sdp);
void read_objectives(const boost::filesystem::path &sdp_directory,
                     const El::Grid &grid, El::BigFloat &objective_const,
                     El::DistMatrix<El::BigFloat> &dual_objective_b);

SDP::SDP(const boost::filesystem::path &sdp_directory,
         const Block_Info &block_info, const El::Grid &grid)
{
  read_objectives(sdp_directory, grid, objective_const, dual_objective_b);
  read_blocks(sdp_directory, grid, block_info, *this);
}

SDP::SDP(
  const El::BigFloat &objective_const_input,
  const std::vector<std::vector<El::BigFloat>> &primal_objective_c_input,
  const std::vector<El::Matrix<El::BigFloat>> &free_var_input,
  const El::DistMatrix<El::BigFloat, El::STAR, El::STAR> &yp_to_y_star,
  const El::DistMatrix<El::BigFloat, El::STAR, El::STAR> &dual_objective_b_star,
  const El::BigFloat &primal_c_scale,
  const Block_Info &block_info, const El::Grid &grid)
    : dual_objective_b(dual_objective_b_star.Height(), 1, grid),
      objective_const(objective_const_input)
{
  std::vector<size_t> block_offsets(primal_objective_c_input.size() + 1, 0);
  for(size_t p(0); p < primal_objective_c_input.size(); ++p)
    {
      block_offsets[p + 1]
        = block_offsets[p] + primal_objective_c_input[p].size();
    }

  auto &block_indices(block_info.block_indices);
  std::vector<El::Matrix<El::BigFloat>> bilinear_bases_local(
    2 * block_indices.size());
  for(size_t block(0); block != block_indices.size(); ++block)
    {
      bilinear_bases_local[2 * block].Resize(1, 1);
      bilinear_bases_local[2 * block + 1].Resize(0, 1);
      bilinear_bases_local[2 * block](0, 0) = 1;
    }
  assign_bilinear_bases_dist(bilinear_bases_local, grid, bilinear_bases);
  set_bases_blocks(block_info, bilinear_bases_local, bases_blocks, grid);

  for(size_t block(0); block != block_indices.size(); ++block)
    {
      primal_objective_c.blocks.emplace_back(
        primal_objective_c_input.at(block_indices.at(block)).size(), 1, grid);
      // TODO: copied from sdp_solve/SDP/SDP/read_primal_objective_c.cxx
      auto &primal_block(primal_objective_c.blocks.back());
      const size_t local_height(primal_block.LocalHeight());
      if(primal_block.GlobalCol(0) == 0)
        {
          for(size_t row = 0; row < local_height; ++row)
            {
              const size_t global_row(primal_block.GlobalRow(row));
              primal_block.SetLocal(
                row, 0,
                primal_c_scale
                  * primal_objective_c_input.at(block_indices.at(block))
                      .at(global_row));
            }
        }
    }

  // Setup B
  const int64_t B_Height(block_offsets.back()),
    B_Width(dual_objective_b_star.Height());
  El::Grid global_grid;
  El::DistMatrix<El::BigFloat> B(B_Height, B_Width, global_grid);

  for(int64_t row(0); row != B.LocalHeight(); ++row)
    {
      const size_t global_row(B.GlobalRow(row));
      const auto upper_iterator(std::upper_bound(
        block_offsets.begin(), block_offsets.end(), global_row));
      const size_t block_index(
        std::distance(block_offsets.begin(), upper_iterator) - 1);
      const size_t block_row(global_row - block_offsets[block_index]);
      for(int64_t column(0); column != B.LocalWidth(); ++column)
        {
          const size_t global_column(B.GlobalCol(column));
          B.SetLocal(
            row, column,
            primal_c_scale
              * free_var_input.at(block_index)(block_row, global_column));
        }
    }

  // Transform B into the yp frame.
  El::DistMatrix<El::BigFloat> U(B.Height(), B.Width(), B.Grid());
  El::Zero(U);
  El::DistMatrix<El::BigFloat> yp_to_y(yp_to_y_star.Height(),
                                       yp_to_y_star.Width(), B.Grid());

  for(int64_t row(0); row < yp_to_y.LocalHeight(); ++row)
    {
      const int64_t global_row(yp_to_y.GlobalRow(row));
      for(int64_t column(0); column < yp_to_y.LocalWidth(); ++column)
        {
          const int64_t global_column(yp_to_y.GlobalCol(column));
          yp_to_y.SetLocal(row, column,
                           yp_to_y_star.GetLocal(global_row, global_column));
        }
    }
  El::Gemm(El::Orientation::NORMAL, El::Orientation::NORMAL, El::BigFloat(1.0),
           B, yp_to_y, El::BigFloat(0.0), U);

  El::DistMatrix<El::BigFloat, El::STAR, El::STAR> U_star(U);

  free_var_matrix.blocks.reserve(block_indices.size());
  for(size_t block(0); block != block_indices.size(); ++block)
    {
      const size_t block_index(block_indices.at(block));
      free_var_matrix.blocks.emplace_back(
        free_var_input.at(block_index).Height(),
        free_var_input.at(block_index).Width(), grid);
      auto &free_var_block(free_var_matrix.blocks.back());
      for(int64_t row(0); row != free_var_block.Height(); ++row)
        {
          const int64_t global_row(block_offsets.at(block_index) + row);
          for(int64_t column(0); column != free_var_block.Width(); ++column)
            {
              if(free_var_block.IsLocal(row, column))
                {
                  free_var_block.SetLocal(free_var_block.LocalRow(row),
                                          free_var_block.LocalCol(column),
                                          U_star.GetLocal(global_row, column));
                }
            }
        }
    }

  // Copy over dual_objective_b
  for(int64_t row(0); row < dual_objective_b.LocalHeight(); ++row)
    {
      const int64_t global_row(dual_objective_b.GlobalRow(row));
      for(int64_t column(0); column < dual_objective_b.LocalWidth(); ++column)
        {
          const int64_t global_column(dual_objective_b.GlobalCol(column));
          dual_objective_b.SetLocal(
            row, column,
            dual_objective_b_star.GetLocal(global_row, global_column));
        }
    }
}
<commit_msg>Reformat<commit_after>#include "assign_bilinear_bases_dist.hxx"
#include "../../SDP.hxx"
#include "set_bases_blocks.hxx"

#include <boost/filesystem.hpp>

#include <iterator>

void read_blocks(const boost::filesystem::path &sdp_directory,
                 const El::Grid &grid, const Block_Info &block_info, SDP &sdp);
void read_objectives(const boost::filesystem::path &sdp_directory,
                     const El::Grid &grid, El::BigFloat &objective_const,
                     El::DistMatrix<El::BigFloat> &dual_objective_b);

SDP::SDP(const boost::filesystem::path &sdp_directory,
         const Block_Info &block_info, const El::Grid &grid)
{
  read_objectives(sdp_directory, grid, objective_const, dual_objective_b);
  read_blocks(sdp_directory, grid, block_info, *this);
}

SDP::SDP(
  const El::BigFloat &objective_const_input,
  const std::vector<std::vector<El::BigFloat>> &primal_objective_c_input,
  const std::vector<El::Matrix<El::BigFloat>> &free_var_input,
  const El::DistMatrix<El::BigFloat, El::STAR, El::STAR> &yp_to_y_star,
  const El::DistMatrix<El::BigFloat, El::STAR, El::STAR> &dual_objective_b_star,
  const El::BigFloat &primal_c_scale, const Block_Info &block_info,
  const El::Grid &grid)
    : dual_objective_b(dual_objective_b_star.Height(), 1, grid),
      objective_const(objective_const_input)
{
  std::vector<size_t> block_offsets(primal_objective_c_input.size() + 1, 0);
  for(size_t p(0); p < primal_objective_c_input.size(); ++p)
    {
      block_offsets[p + 1]
        = block_offsets[p] + primal_objective_c_input[p].size();
    }

  auto &block_indices(block_info.block_indices);
  std::vector<El::Matrix<El::BigFloat>> bilinear_bases_local(
    2 * block_indices.size());
  for(size_t block(0); block != block_indices.size(); ++block)
    {
      bilinear_bases_local[2 * block].Resize(1, 1);
      bilinear_bases_local[2 * block + 1].Resize(0, 1);
      bilinear_bases_local[2 * block](0, 0) = 1;
    }
  assign_bilinear_bases_dist(bilinear_bases_local, grid, bilinear_bases);
  set_bases_blocks(block_info, bilinear_bases_local, bases_blocks, grid);

  for(size_t block(0); block != block_indices.size(); ++block)
    {
      primal_objective_c.blocks.emplace_back(
        primal_objective_c_input.at(block_indices.at(block)).size(), 1, grid);
      // TODO: copied from sdp_solve/SDP/SDP/read_primal_objective_c.cxx
      auto &primal_block(primal_objective_c.blocks.back());
      const size_t local_height(primal_block.LocalHeight());
      if(primal_block.GlobalCol(0) == 0)
        {
          for(size_t row = 0; row < local_height; ++row)
            {
              const size_t global_row(primal_block.GlobalRow(row));
              primal_block.SetLocal(
                row, 0,
                primal_c_scale
                  * primal_objective_c_input.at(block_indices.at(block))
                      .at(global_row));
            }
        }
    }

  // Setup B
  const int64_t B_Height(block_offsets.back()),
    B_Width(dual_objective_b_star.Height());
  El::Grid global_grid;
  El::DistMatrix<El::BigFloat> B(B_Height, B_Width, global_grid);

  for(int64_t row(0); row != B.LocalHeight(); ++row)
    {
      const size_t global_row(B.GlobalRow(row));
      const auto upper_iterator(std::upper_bound(
        block_offsets.begin(), block_offsets.end(), global_row));
      const size_t block_index(
        std::distance(block_offsets.begin(), upper_iterator) - 1);
      const size_t block_row(global_row - block_offsets[block_index]);
      for(int64_t column(0); column != B.LocalWidth(); ++column)
        {
          const size_t global_column(B.GlobalCol(column));
          B.SetLocal(
            row, column,
            primal_c_scale
              * free_var_input.at(block_index)(block_row, global_column));
        }
    }

  // Transform B into the yp frame.
  El::DistMatrix<El::BigFloat> U(B.Height(), B.Width(), B.Grid());
  El::Zero(U);
  El::DistMatrix<El::BigFloat> yp_to_y(yp_to_y_star.Height(),
                                       yp_to_y_star.Width(), B.Grid());

  for(int64_t row(0); row < yp_to_y.LocalHeight(); ++row)
    {
      const int64_t global_row(yp_to_y.GlobalRow(row));
      for(int64_t column(0); column < yp_to_y.LocalWidth(); ++column)
        {
          const int64_t global_column(yp_to_y.GlobalCol(column));
          yp_to_y.SetLocal(row, column,
                           yp_to_y_star.GetLocal(global_row, global_column));
        }
    }
  El::Gemm(El::Orientation::NORMAL, El::Orientation::NORMAL, El::BigFloat(1.0),
           B, yp_to_y, El::BigFloat(0.0), U);

  El::DistMatrix<El::BigFloat, El::STAR, El::STAR> U_star(U);

  free_var_matrix.blocks.reserve(block_indices.size());
  for(size_t block(0); block != block_indices.size(); ++block)
    {
      const size_t block_index(block_indices.at(block));
      free_var_matrix.blocks.emplace_back(
        free_var_input.at(block_index).Height(),
        free_var_input.at(block_index).Width(), grid);
      auto &free_var_block(free_var_matrix.blocks.back());
      for(int64_t row(0); row != free_var_block.Height(); ++row)
        {
          const int64_t global_row(block_offsets.at(block_index) + row);
          for(int64_t column(0); column != free_var_block.Width(); ++column)
            {
              if(free_var_block.IsLocal(row, column))
                {
                  free_var_block.SetLocal(free_var_block.LocalRow(row),
                                          free_var_block.LocalCol(column),
                                          U_star.GetLocal(global_row, column));
                }
            }
        }
    }

  // Copy over dual_objective_b
  for(int64_t row(0); row < dual_objective_b.LocalHeight(); ++row)
    {
      const int64_t global_row(dual_objective_b.GlobalRow(row));
      for(int64_t column(0); column < dual_objective_b.LocalWidth(); ++column)
        {
          const int64_t global_column(dual_objective_b.GlobalCol(column));
          dual_objective_b.SetLocal(
            row, column,
            dual_objective_b_star.GetLocal(global_row, global_column));
        }
    }
}
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of charge propagation module with transient behavior simulation
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "TransientPropagationModule.hpp"

#include <map>
#include <memory>
#include <random>
#include <string>
#include <utility>

#include <Eigen/Core>

#include "core/utils/log.h"
#include "tools/runge_kutta.h"

using namespace allpix;

TransientPropagationModule::TransientPropagationModule(Configuration& config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), detector_(std::move(detector)), messenger_(messenger) {

    // Save detector model
    model_ = detector_->getModel();

    // Require deposits message for single detector:
    messenger_->bindSingle(this, &TransientPropagationModule::deposits_message_, MsgFlags::REQUIRED);

    // Seed the random generator with the module seed
    random_generator_.seed(getRandomSeed());

    // Set default value for config variables
    config_.setDefault<double>("spatial_precision", Units::get(0.25, "nm"));
    config_.setDefault<double>("timestep", Units::get(0.01, "ns"));
    config_.setDefault<double>("integration_time", Units::get(25, "ns"));
    config_.setDefault<unsigned int>("charge_per_step", 10);
    config_.setDefault<double>("temperature", 293.15);

    // Parameterization variables from https://doi.org/10.1016/0038-1101(77)90054-5 (section 5.2)
    electron_Vm_ = Units::get(1.53e9 * std::pow(temperature_, -0.87), "cm/s");
    electron_Ec_ = Units::get(1.01 * std::pow(temperature_, 1.55), "V/cm");
    electron_Beta_ = 2.57e-2 * std::pow(temperature_, 0.66);

    hole_Vm_ = Units::get(1.62e8 * std::pow(temperature_, -0.52), "cm/s");
    hole_Ec_ = Units::get(1.24 * std::pow(temperature_, 1.68), "V/cm");
    hole_Beta_ = 0.46 * std::pow(temperature_, 0.17);

    boltzmann_kT_ = Units::get(8.6173e-5, "eV/K") * temperature_;
}

void TransientPropagationModule::init() {

    // FIXME check that we have a Ramo Weighting field for the detector!
}

void TransientPropagationModule::run(unsigned int) {

    // Create map for all pixels
    std::map<Pixel::Index, PixelPulse> pixel_map;

    // Loop over all deposits for propagation
    LOG(TRACE) << "Propagating charges in sensor";
    for(auto& deposit : deposits_message_->getData()) {

        // Loop over all charges in the deposit
        unsigned int charges_remaining = deposit.getCharge();

        LOG(DEBUG) << "Set of charge carriers (" << deposit.getType() << ") on "
                   << Units::display(deposit.getLocalPosition(), {"mm", "um"});

        auto charge_per_step = config_.get<unsigned int>("charge_per_step");
        while(charges_remaining > 0) {
            // Define number of charges to be propagated and remove charges of this step from the total
            if(charge_per_step > charges_remaining) {
                charge_per_step = charges_remaining;
            }
            charges_remaining -= charge_per_step;

            // Get position and propagate through sensor
            auto position = deposit.getLocalPosition();

            // Propagate a single charge deposit
            propagate(position, deposit.getType(), charge_per_step, pixel_map);
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelPulse> pixel_pulses;
    for(auto& pixel_index_pulse : pixel_map) {
        pixel_pulses.push_back(std::move(pixel_index_pulse.second));
    }

    // Create a new message with pixel pulses
    auto pixel_pulse_message = std::make_shared<PixelPulseMessage>(std::move(pixel_pulses), detector_);

    // Dispatch the message with pixel pulses
    messenger_->dispatchMessage(this, pixel_pulse_message);
}

/**
 * Propagation is simulated using a parameterization for the electron mobility. This is used to calculate the electron
 * velocity at every point with help of the electric field map of the detector. A Runge-Kutta integration is applied in
 * multiple steps, adding a random diffusion to the propagating charge every step.
 */
void TransientPropagationModule::propagate(const ROOT::Math::XYZPoint& pos,
                                           const CarrierType& type,
                                           const unsigned int,
                                           std::map<Pixel::Index, PixelPulse>&) {

    // Create a runge kutta solver using the electric field as step function
    Eigen::Vector3d position(pos.x(), pos.y(), pos.z());

    // Define a lambda function to compute the carrier mobility
    // NOTE This function is typically the most frequently executed part of the framework and therefore the bottleneck
    auto carrier_mobility = [&](double efield_mag) {
        // Compute carrier mobility from constants and electric field magnitude
        double numerator, denominator;
        if(type == CarrierType::ELECTRON) {
            numerator = electron_Vm_ / electron_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / electron_Ec_, electron_Beta_), 1.0 / electron_Beta_);
        } else {
            numerator = hole_Vm_ / hole_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / hole_Ec_, hole_Beta_), 1.0 / hole_Beta_);
        }
        return numerator / denominator;
    };

    // Define a function to compute the diffusion
    auto carrier_diffusion = [&](double efield_mag, double timestep) -> Eigen::Vector3d {
        double diffusion_constant = boltzmann_kT_ * carrier_mobility(efield_mag);
        double diffusion_std_dev = std::sqrt(2. * diffusion_constant * timestep);

        // Compute the independent diffusion in three
        std::normal_distribution<double> gauss_distribution(0, diffusion_std_dev);
        Eigen::Vector3d diffusion;
        for(int i = 0; i < 3; ++i) {
            diffusion[i] = gauss_distribution(random_generator_);
        }
        return diffusion;
    };

    // Define a lambda function to compute the electron velocity
    auto carrier_velocity = [&](double, Eigen::Vector3d cur_pos) -> Eigen::Vector3d {
        auto raw_field = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(cur_pos));
        // Compute the drift velocity
        Eigen::Vector3d efield(raw_field.x(), raw_field.y(), raw_field.z());

        return static_cast<int>(type) * carrier_mobility(efield.norm()) * efield;
    };

    // Create the runge kutta solver with an RKF5 tableau
    auto runge_kutta = make_runge_kutta(tableau::RK5, carrier_velocity, timestep_, position);

    // Continue propagation until the deposit is outside the sensor
    Eigen::Vector3d last_position = position;
    double last_time = 0;
    while(detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position)) &&
          runge_kutta.getTime() < integration_time_) {

        // Save previous position and time
        last_position = position;
        last_time = runge_kutta.getTime();

        // Execute a Runge Kutta step
        // FIXME the central call to the RKF integrator:
        // auto step = runge_kutta.step();

        // Get the current result
        position = runge_kutta.getValue();

        // Get electric field at current position and fall back to empty field if it does not exist
        auto efield = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(position));

        // Apply diffusion step
        auto diffusion = carrier_diffusion(std::sqrt(efield.Mag2()), timestep_);
        position += diffusion;

        // TODO implement calculation of Ramo induced charge
        // TODO loop over NxN pixels and add it to their respective pulses
    }

    // Find proper final position in the sensor
    auto time = runge_kutta.getTime();
    if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
        auto check_position = position;
        check_position.z() = last_position.z();
        if(position.z() > 0 && detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(check_position))) {
            // Carrier left sensor on the side of the pixel grid, interpolate end point on surface
            auto z_cur_border = std::fabs(position.z() - model_->getSensorSize().z() / 2.0);
            auto z_last_border = std::fabs(model_->getSensorSize().z() / 2.0 - last_position.z());
            auto z_total = z_cur_border + z_last_border;
            position = (z_last_border / z_total) * position + (z_cur_border / z_total) * last_position;
            time = (z_last_border / z_total) * time + (z_cur_border / z_total) * last_time;
        } else {
            // Carrier left sensor on any order border, use last position inside instead
            position = last_position;
            time = last_time;
        }
        LOG(TRACE) << "Time: " << Units::display(time, {"ps", "ns"});
    }
}
<commit_msg>TransientProp: cache a few variables<commit_after>/**
 * @file
 * @brief Implementation of charge propagation module with transient behavior simulation
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "TransientPropagationModule.hpp"

#include <map>
#include <memory>
#include <random>
#include <string>
#include <utility>

#include <Eigen/Core>

#include "core/utils/log.h"
#include "tools/runge_kutta.h"

using namespace allpix;

TransientPropagationModule::TransientPropagationModule(Configuration& config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), detector_(std::move(detector)), messenger_(messenger) {

    // Save detector model
    model_ = detector_->getModel();

    // Require deposits message for single detector:
    messenger_->bindSingle(this, &TransientPropagationModule::deposits_message_, MsgFlags::REQUIRED);

    // Seed the random generator with the module seed
    random_generator_.seed(getRandomSeed());

    // Set default value for config variables
    config_.setDefault<double>("timestep", Units::get(0.01, "ns"));
    config_.setDefault<double>("integration_time", Units::get(25, "ns"));
    config_.setDefault<unsigned int>("charge_per_step", 10);
    config_.setDefault<double>("temperature", 293.15);

    // Copy some variables from configuration to avoid lookups:
    temperature_ = config_.get<double>("temperature");
    timestep_ = config_.get<double>("timestep");
    integration_time_ = config_.get<double>("integration_time");

    // Parameterization variables from https://doi.org/10.1016/0038-1101(77)90054-5 (section 5.2)
    electron_Vm_ = Units::get(1.53e9 * std::pow(temperature_, -0.87), "cm/s");
    electron_Ec_ = Units::get(1.01 * std::pow(temperature_, 1.55), "V/cm");
    electron_Beta_ = 2.57e-2 * std::pow(temperature_, 0.66);

    hole_Vm_ = Units::get(1.62e8 * std::pow(temperature_, -0.52), "cm/s");
    hole_Ec_ = Units::get(1.24 * std::pow(temperature_, 1.68), "V/cm");
    hole_Beta_ = 0.46 * std::pow(temperature_, 0.17);

    boltzmann_kT_ = Units::get(8.6173e-5, "eV/K") * temperature_;
}

void TransientPropagationModule::init() {

    // FIXME check that we have a Ramo Weighting field for the detector!
}

void TransientPropagationModule::run(unsigned int) {

    // Create map for all pixels
    std::map<Pixel::Index, PixelPulse> pixel_map;

    // Loop over all deposits for propagation
    LOG(TRACE) << "Propagating charges in sensor";
    for(auto& deposit : deposits_message_->getData()) {

        // Loop over all charges in the deposit
        unsigned int charges_remaining = deposit.getCharge();

        LOG(DEBUG) << "Set of charge carriers (" << deposit.getType() << ") on "
                   << Units::display(deposit.getLocalPosition(), {"mm", "um"});

        auto charge_per_step = config_.get<unsigned int>("charge_per_step");
        while(charges_remaining > 0) {
            // Define number of charges to be propagated and remove charges of this step from the total
            if(charge_per_step > charges_remaining) {
                charge_per_step = charges_remaining;
            }
            charges_remaining -= charge_per_step;

            // Get position and propagate through sensor
            auto position = deposit.getLocalPosition();

            // Propagate a single charge deposit
            propagate(position, deposit.getType(), charge_per_step, pixel_map);
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelPulse> pixel_pulses;
    for(auto& pixel_index_pulse : pixel_map) {
        pixel_pulses.push_back(std::move(pixel_index_pulse.second));
    }

    // Create a new message with pixel pulses
    auto pixel_pulse_message = std::make_shared<PixelPulseMessage>(std::move(pixel_pulses), detector_);

    // Dispatch the message with pixel pulses
    messenger_->dispatchMessage(this, pixel_pulse_message);
}

/**
 * Propagation is simulated using a parameterization for the electron mobility. This is used to calculate the electron
 * velocity at every point with help of the electric field map of the detector. A Runge-Kutta integration is applied in
 * multiple steps, adding a random diffusion to the propagating charge every step.
 */
void TransientPropagationModule::propagate(const ROOT::Math::XYZPoint& pos,
                                           const CarrierType& type,
                                           const unsigned int,
                                           std::map<Pixel::Index, PixelPulse>&) {

    // Create a runge kutta solver using the electric field as step function
    Eigen::Vector3d position(pos.x(), pos.y(), pos.z());

    // Define a lambda function to compute the carrier mobility
    // NOTE This function is typically the most frequently executed part of the framework and therefore the bottleneck
    auto carrier_mobility = [&](double efield_mag) {
        // Compute carrier mobility from constants and electric field magnitude
        double numerator, denominator;
        if(type == CarrierType::ELECTRON) {
            numerator = electron_Vm_ / electron_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / electron_Ec_, electron_Beta_), 1.0 / electron_Beta_);
        } else {
            numerator = hole_Vm_ / hole_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / hole_Ec_, hole_Beta_), 1.0 / hole_Beta_);
        }
        return numerator / denominator;
    };

    // Define a function to compute the diffusion
    auto carrier_diffusion = [&](double efield_mag, double timestep) -> Eigen::Vector3d {
        double diffusion_constant = boltzmann_kT_ * carrier_mobility(efield_mag);
        double diffusion_std_dev = std::sqrt(2. * diffusion_constant * timestep);

        // Compute the independent diffusion in three
        std::normal_distribution<double> gauss_distribution(0, diffusion_std_dev);
        Eigen::Vector3d diffusion;
        for(int i = 0; i < 3; ++i) {
            diffusion[i] = gauss_distribution(random_generator_);
        }
        return diffusion;
    };

    // Define a lambda function to compute the electron velocity
    auto carrier_velocity = [&](double, Eigen::Vector3d cur_pos) -> Eigen::Vector3d {
        auto raw_field = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(cur_pos));
        // Compute the drift velocity
        Eigen::Vector3d efield(raw_field.x(), raw_field.y(), raw_field.z());

        return static_cast<int>(type) * carrier_mobility(efield.norm()) * efield;
    };

    // Create the runge kutta solver with an RKF5 tableau
    auto runge_kutta = make_runge_kutta(tableau::RK5, carrier_velocity, timestep_, position);

    // Continue propagation until the deposit is outside the sensor
    Eigen::Vector3d last_position = position;
    double last_time = 0;
    while(detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position)) &&
          runge_kutta.getTime() < integration_time_) {

        // Save previous position and time
        last_position = position;
        last_time = runge_kutta.getTime();

        // Execute a Runge Kutta step
        runge_kutta.step();

        // Get the current result
        position = runge_kutta.getValue();

        // Get electric field at current position and fall back to empty field if it does not exist
        auto efield = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(position));

        // Apply diffusion step
        auto diffusion = carrier_diffusion(std::sqrt(efield.Mag2()), timestep_);
        position += diffusion;

        // TODO implement calculation of Ramo induced charge
        // TODO loop over NxN pixels and add it to their respective pulses
    }

    // Find proper final position in the sensor
    auto time = runge_kutta.getTime();
    if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
        auto check_position = position;
        check_position.z() = last_position.z();
        if(position.z() > 0 && detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(check_position))) {
            // Carrier left sensor on the side of the pixel grid, interpolate end point on surface
            auto z_cur_border = std::fabs(position.z() - model_->getSensorSize().z() / 2.0);
            auto z_last_border = std::fabs(model_->getSensorSize().z() / 2.0 - last_position.z());
            auto z_total = z_cur_border + z_last_border;
            position = (z_last_border / z_total) * position + (z_cur_border / z_total) * last_position;
            time = (z_last_border / z_total) * time + (z_cur_border / z_total) * last_time;
        } else {
            // Carrier left sensor on any order border, use last position inside instead
            position = last_position;
            time = last_time;
        }
        LOG(TRACE) << "Time: " << Units::display(time, {"ps", "ns"});
    }
}
<|endoftext|>


<commit_before>/*
 * SessionRmdNotebook.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"

#include <iostream>

#include <boost/foreach.hpp>

#include <r/RJson.hpp>
#include <r/RExec.hpp>

#include <core/Exec.hpp>
#include <core/FileSerializer.hpp>
#include <core/Algorithm.hpp>
#include <core/json/Json.hpp>
#include <core/json/JsonRpc.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/SessionSourceDatabase.hpp>

#define kChunkDefs        "chunk_definitions"
#define kChunkOutputPath  "chunk_output"
#define kChunkLibDir      "chunk-lib"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {

namespace {

FilePath chunkCacheFolder(const std::string& docPath, const std::string& docId)
{
   FilePath folder;
   std::string stem;
   if (docPath.empty())
   {
      folder = module_context::userScratchPath().childPath("unsaved-notebooks");
      stem = docId;
   }
   else
   {
      FilePath path = module_context::resolveAliasedPath(docPath);
      stem = path.stem();
      folder = path.parent();
   }

   return folder.childPath(stem + ".Rnb.cached");
}

FilePath chunkDefinitionsPath(
      const std::string& docPath, const std::string& docId)
{
   return chunkCacheFolder(docPath, docId).childPath("chunks.json");
}

FilePath chunkOutputPath(
      const std::string& docPath, const std::string& docId,
      const std::string& chunkId)
{
   return chunkCacheFolder(docPath, docId)
                          .childPath(chunkId + ".html");
}

Error enqueueChunkOutput(
      const std::string& docPath, const std::string& docId,
      const std::string& chunkId)
{
   json::Object output;
   output["url"] = kChunkOutputPath "/" + docId + "/" + chunkId + ".html";
   output["chunk_id"] = chunkId;
   output["doc_id"] = docId;
   ClientEvent event(client_events::kChunkOutput, output);
   module_context::enqueClientEvent(event);

   return Success();
}

Error executeInlineChunk(const json::JsonRpcRequest& request,
                         json::JsonRpcResponse*)
{
   std::string docPath, docId, chunkId, options, content;
   Error error = json::readParams(request.params, &docPath, &docId, &chunkId,
         &options, &content);
   if (error)
      return error;

   // ensure we have a place to put the output
   FilePath chunkOutput = chunkOutputPath(docPath, docId, chunkId);
   error = chunkOutput.parent().ensureDirectory();
   if (error)
      return error;

   // ensure we have a library path
   FilePath chunkLibDir = chunkCacheFolder(docPath, docId).complete(
         kChunkLibDir);
   error = chunkLibDir.ensureDirectory();
   if (error)
      return error;

   // render the contents to the cached folder, then extract the contents
   error = r::exec::RFunction(".rs.executeSingleChunk", options, content,
         chunkLibDir.absolutePath(),
         chunkOutput.absolutePath()).call();
   if (error)
      return error;

   error = enqueueChunkOutput(docPath, docId, chunkId);

   return Success();
}

void replayChunkOutputs(const std::string& docPath, const std::string& docId,
      const std::string& requestId, const json::Array& chunkOutputs)
{
   // find all the chunks and play them back to the client
   BOOST_FOREACH(const json::Value& chunkOutput, chunkOutputs)
   {
      if (chunkOutput.type() != json::ObjectType)
         continue;
      std::string chunkId;
      if (json::readObject(chunkOutput.get_obj(), "chunk_id", &chunkId) ==
            Success())
      {
         // ignore errors here (it's okay if some chunks don't have output)
         enqueueChunkOutput(docPath, docId, chunkId);
      }
   }

   json::Object result;
   result["path"] = docPath;
   result["request_id"] = requestId;
   ClientEvent event(client_events::kChunkOutputFinished, result);
   module_context::enqueClientEvent(event);
}

Error refreshChunkOutput(const json::JsonRpcRequest& request,
                     json::JsonRpcResponse*)
{
   // extract path to doc to be refreshed
   std::string docPath, docId, requestId;
   Error error = json::readParams(request.params, &docPath, &docId, &requestId);
   if (error)
      return error;

   json::Object result;
   json::Value chunkDefs;
   error = getChunkDefs(docPath, docId, &chunkDefs);

   // schedule the work to play back the chunks (we don't do it synchronously
   // so the RPC can return immediately)
   if (!error && chunkDefs.type() == json::ArrayType)
   {
      module_context::scheduleDelayedWork(boost::posix_time::milliseconds(10),
            boost::bind(replayChunkOutputs, docPath, docId, requestId,
                        chunkDefs.get_array()));
   }

   return Success();
}

bool copyCacheItem(const FilePath& from,
                   const FilePath& to,
                   const FilePath& path)
{

   std::string relativePath = path.relativePath(from);
   FilePath target = to.complete(relativePath);

   Error error = path.isDirectory() ?
                     target.ensureDirectory() :
                     path.copy(target);
   if (error)
      LOG_ERROR(error);

   return true;
}

Error copyCache(const FilePath& from, const FilePath& to)
{
   Error error = to.ensureDirectory();
   if (error)
      return error;

   return from.childrenRecursive(
             boost::bind(copyCacheItem, from, to, _2));
}

void onDocRemoved(const std::string& docId)
{
   // check to see if this document was an unsaved notebook, and clean up its
   // cache folder if so
   FilePath cacheFolder = chunkCacheFolder("", docId);
   Error error = cacheFolder.removeIfExists();
   if (error)
      LOG_ERROR(error);
}

void onDocRenamed(const std::string& oldPath,
                  boost::shared_ptr<source_database::SourceDocument> pDoc)
{
   // compute cache folders and ignore if we can't safely adjust them
   FilePath oldCacheDir = chunkCacheFolder(oldPath, pDoc->id());
   FilePath newCacheDir = chunkCacheFolder(pDoc->path(), pDoc->id());
   if (!oldCacheDir.exists() || newCacheDir.exists())
      return;

   // if the doc was previously unsaved, we can just move the whole folder
   // to its newly saved location
   if (oldPath.empty())
   {
      oldCacheDir.move(newCacheDir);
      return;
   }

   Error error = copyCache(oldCacheDir, newCacheDir);
   if (error)
      LOG_ERROR(error);
}

Error handleChunkOutputRequest(const http::Request& request,
                               http::Response* pResponse)
{
   // uri format is: /chunk_output/<doc-id>/...

   // split URI into pieces, extract the chunk and document ID, and remove that
   // part of the URI
   std::vector<std::string> parts = algorithm::split(request.uri(), "/");
   if (parts.size() < 4)
      return Success();
   std::string docId = parts[2];
   for (int i = 0; i < 3; i++)
      parts.erase(parts.begin());

   std::string path;
   Error error = source_database::getPath(docId, &path);
   if (error)
      return error;
   FilePath target = chunkCacheFolder(path, docId).complete(
         algorithm::join(parts, "/"));

   // if a reference to the chunk library folder, we can reuse the contents
   if (parts[0] == kChunkLibDir)
   {
      pResponse->setCacheableFile(target, request);
   }
   else
   {
      pResponse->setNoCacheHeaders();
      pResponse->setFile(target, request);
   }

   return Success();
}

} // anonymous namespace

Error setChunkDefs(const std::string& docPath, const std::string& docId,
                   const json::Array& pDefs)
{
   // create JSON object wrapping
   json::Object chunkDefs;
   chunkDefs[kChunkDefs] = pDefs;

   // ensure we have a place to write the sidecar file
   FilePath defFile = chunkDefinitionsPath(docPath, docId);
   Error error = defFile.parent().ensureDirectory();
   if (error)
      return error;

   // write to the sidecar file
   std::ostringstream oss;
   json::write(chunkDefs, oss);
   return writeStringToFile(defFile, oss.str());
}

Error getChunkDefs(const std::string& docPath, const std::string& docId,
                   core::json::Value* pDefs)
{
   Error error;
   FilePath defs = chunkDefinitionsPath(docPath, docId);
   if (!defs.exists())
      return Success();

   // read the defs file
   std::string contents;
   error = readStringFromFile(defs, &contents);
   if (error)
      return error;

   // pull out the contents
   json::Value defContents;
   if (!json::parse(contents, &defContents) ||
       defContents.type() != json::ObjectType)
      return Error(json::errc::ParseError, ERROR_LOCATION);

   // extract the chunk definitions
   json::Array chunkDefs;
   error = json::readObject(defContents.get_obj(), kChunkDefs, &chunkDefs);
   if (error)
      return error;

   // return to caller
   *pDefs = chunkDefs;
   return Success();
}

Error initialize()
{
   using boost::bind;
   using namespace module_context;

   source_database::events().onDocRenamed.connect(onDocRenamed);
   source_database::events().onDocRemoved.connect(onDocRemoved);

   ExecBlock initBlock;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "execute_inline_chunk", executeInlineChunk))
      (bind(registerRpcMethod, "refresh_chunk_output", refreshChunkOutput))
      (bind(registerUriHandler, "/" kChunkOutputPath,
            handleChunkOutputRequest))
      (bind(module_context::sourceModuleRFile, "SessionRmdNotebook.R"));

   return initBlock.execute();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<commit_msg>clean up chunk output HTML after chunk is removed from doc<commit_after>/*
 * SessionRmdNotebook.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"

#include <iostream>

#include <boost/foreach.hpp>

#include <r/RJson.hpp>
#include <r/RExec.hpp>

#include <core/Exec.hpp>
#include <core/FileSerializer.hpp>
#include <core/Algorithm.hpp>
#include <core/json/Json.hpp>
#include <core/json/JsonRpc.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/SessionSourceDatabase.hpp>

#define kChunkDefs        "chunk_definitions"
#define kChunkOutputPath  "chunk_output"
#define kChunkLibDir      "lib"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {

namespace {

FilePath chunkCacheFolder(const std::string& docPath, const std::string& docId)
{
   FilePath folder;
   std::string stem;
   if (docPath.empty())
   {
      folder = module_context::userScratchPath().childPath("unsaved-notebooks");
      stem = docId;
   }
   else
   {
      FilePath path = module_context::resolveAliasedPath(docPath);
      stem = path.stem();
      folder = path.parent();
   }

   return folder.childPath(stem + ".Rnb.cached");
}

FilePath chunkDefinitionsPath(
      const std::string& docPath, const std::string& docId)
{
   return chunkCacheFolder(docPath, docId).childPath("chunks.json");
}

FilePath chunkOutputPath(
      const std::string& docPath, const std::string& docId,
      const std::string& chunkId)
{
   return chunkCacheFolder(docPath, docId)
                          .childPath(chunkId + ".html");
}

Error enqueueChunkOutput(
      const std::string& docPath, const std::string& docId,
      const std::string& chunkId)
{
   json::Object output;
   output["url"] = kChunkOutputPath "/" + docId + "/" + chunkId + ".html";
   output["chunk_id"] = chunkId;
   output["doc_id"] = docId;
   ClientEvent event(client_events::kChunkOutput, output);
   module_context::enqueClientEvent(event);

   return Success();
}

Error executeInlineChunk(const json::JsonRpcRequest& request,
                         json::JsonRpcResponse*)
{
   std::string docPath, docId, chunkId, options, content;
   Error error = json::readParams(request.params, &docPath, &docId, &chunkId,
         &options, &content);
   if (error)
      return error;

   // ensure we have a place to put the output
   FilePath chunkOutput = chunkOutputPath(docPath, docId, chunkId);
   error = chunkOutput.parent().ensureDirectory();
   if (error)
      return error;

   // ensure we have a library path
   FilePath chunkLibDir = chunkCacheFolder(docPath, docId).complete(
         kChunkLibDir);
   error = chunkLibDir.ensureDirectory();
   if (error)
      return error;

   // render the contents to the cached folder, then extract the contents
   error = r::exec::RFunction(".rs.executeSingleChunk", options, content,
         chunkLibDir.absolutePath(),
         chunkOutput.absolutePath()).call();
   if (error)
      return error;

   error = enqueueChunkOutput(docPath, docId, chunkId);

   return Success();
}

void extractChunkIds(const json::Array& chunkOutputs,
                     std::vector<std::string> *pIds)
{
   BOOST_FOREACH(const json::Value& chunkOutput, chunkOutputs)
   {
      if (chunkOutput.type() != json::ObjectType)
         continue;
      std::string chunkId;
      if (json::readObject(chunkOutput.get_obj(), "chunk_id", &chunkId) ==
            Success())
      {
         pIds->push_back(chunkId);
      }
   }
}

void replayChunkOutputs(const std::string& docPath, const std::string& docId,
      const std::string& requestId, const json::Array& chunkOutputs)
{
   std::vector<std::string> chunkIds;
   extractChunkIds(chunkOutputs, &chunkIds);

   // find all the chunks and play them back to the client
   BOOST_FOREACH(const std::string& chunkId, chunkIds)
   {
      enqueueChunkOutput(docPath, docId, chunkId);
   }

   json::Object result;
   result["path"] = docPath;
   result["request_id"] = requestId;
   ClientEvent event(client_events::kChunkOutputFinished, result);
   module_context::enqueClientEvent(event);
}

Error refreshChunkOutput(const json::JsonRpcRequest& request,
                     json::JsonRpcResponse*)
{
   // extract path to doc to be refreshed
   std::string docPath, docId, requestId;
   Error error = json::readParams(request.params, &docPath, &docId, &requestId);
   if (error)
      return error;

   json::Object result;
   json::Value chunkDefs;
   error = getChunkDefs(docPath, docId, &chunkDefs);

   // schedule the work to play back the chunks (we don't do it synchronously
   // so the RPC can return immediately)
   if (!error && chunkDefs.type() == json::ArrayType)
   {
      module_context::scheduleDelayedWork(boost::posix_time::milliseconds(10),
            boost::bind(replayChunkOutputs, docPath, docId, requestId,
                        chunkDefs.get_array()));
   }

   return Success();
}

bool copyCacheItem(const FilePath& from,
                   const FilePath& to,
                   const FilePath& path)
{

   std::string relativePath = path.relativePath(from);
   FilePath target = to.complete(relativePath);

   Error error = path.isDirectory() ?
                     target.ensureDirectory() :
                     path.copy(target);
   if (error)
      LOG_ERROR(error);

   return true;
}

Error copyCache(const FilePath& from, const FilePath& to)
{
   Error error = to.ensureDirectory();
   if (error)
      return error;

   return from.childrenRecursive(
             boost::bind(copyCacheItem, from, to, _2));
}

void onDocRemoved(const std::string& docId)
{
   // check to see if this document was an unsaved notebook, and clean up its
   // cache folder if so
   FilePath cacheFolder = chunkCacheFolder("", docId);
   Error error = cacheFolder.removeIfExists();
   if (error)
      LOG_ERROR(error);
}

void onDocRenamed(const std::string& oldPath,
                  boost::shared_ptr<source_database::SourceDocument> pDoc)
{
   // compute cache folders and ignore if we can't safely adjust them
   FilePath oldCacheDir = chunkCacheFolder(oldPath, pDoc->id());
   FilePath newCacheDir = chunkCacheFolder(pDoc->path(), pDoc->id());
   if (!oldCacheDir.exists() || newCacheDir.exists())
      return;

   // if the doc was previously unsaved, we can just move the whole folder
   // to its newly saved location
   if (oldPath.empty())
   {
      oldCacheDir.move(newCacheDir);
      return;
   }

   Error error = copyCache(oldCacheDir, newCacheDir);
   if (error)
      LOG_ERROR(error);
}

Error handleChunkOutputRequest(const http::Request& request,
                               http::Response* pResponse)
{
   // uri format is: /chunk_output/<doc-id>/...

   // split URI into pieces, extract the chunk and document ID, and remove that
   // part of the URI
   std::vector<std::string> parts = algorithm::split(request.uri(), "/");
   if (parts.size() < 4)
      return Success();
   std::string docId = parts[2];
   for (int i = 0; i < 3; i++)
      parts.erase(parts.begin());

   std::string path;
   Error error = source_database::getPath(docId, &path);
   if (error)
      return error;
   FilePath target = chunkCacheFolder(path, docId).complete(
         algorithm::join(parts, "/"));

   // if a reference to the chunk library folder, we can reuse the contents
   if (parts[0] == kChunkLibDir)
   {
      pResponse->setCacheableFile(target, request);
   }
   else
   {
      pResponse->setNoCacheHeaders();
      pResponse->setFile(target, request);
   }

   return Success();
}

// given and old and new set of chunk definitions, cleans up all the chunks
// files in the old set but not in the new set
void cleanChunks(const FilePath& cacheDir,
                 const json::Array &oldDefs,
                 const json::Array &newDefs)
{
   Error error;
   std::vector<std::string> oldIds, newIds;

   // extract chunk IDs from JSON objects
   extractChunkIds(oldDefs, &oldIds);
   extractChunkIds(newDefs, &newIds);

   // compute the set of stale IDs
   std::vector<std::string> staleIds;
   std::sort(oldIds.begin(), oldIds.end());
   std::sort(newIds.begin(), newIds.end());
   std::set_difference(oldIds.begin(), oldIds.end(),
                       newIds.begin(), newIds.end(),
                       std::back_inserter(staleIds));

   BOOST_FOREACH(const std::string& staleId, staleIds)
   {
      // clean chunk HTML if present
      cacheDir.complete(staleId + ".html").removeIfExists();
      cacheDir.complete(staleId + "_files").removeIfExists();
   }
}

} // anonymous namespace

Error setChunkDefs(const std::string& docPath, const std::string& docId,
                   const json::Array& newDefs)
{
   // create JSON object wrapping
   json::Object chunkDefs;
   chunkDefs[kChunkDefs] = newDefs;

   // ensure we have a place to write the sidecar file
   FilePath defFile = chunkDefinitionsPath(docPath, docId);
   Error error = defFile.parent().ensureDirectory();
   if (error)
      return error;

   // get the old set of chunk IDs so we can clean up any not in the new set
   // of chunks
   std::vector<std::string> chunkIds;
   json::Value oldDefs;
   error = getChunkDefs(docPath, docId, &oldDefs);
   if (error)
      LOG_ERROR(error);
   else if (oldDefs.type() == json::ArrayType)
      cleanChunks(chunkCacheFolder(docPath, docId),
                  oldDefs.get_array(), newDefs);

   // write to the sidecar file
   std::ostringstream oss;
   json::write(chunkDefs, oss);
   return writeStringToFile(defFile, oss.str());
}

Error getChunkDefs(const std::string& docPath, const std::string& docId,
                   core::json::Value* pDefs)
{
   Error error;
   FilePath defs = chunkDefinitionsPath(docPath, docId);
   if (!defs.exists())
      return Success();

   // read the defs file
   std::string contents;
   error = readStringFromFile(defs, &contents);
   if (error)
      return error;

   // pull out the contents
   json::Value defContents;
   if (!json::parse(contents, &defContents) ||
       defContents.type() != json::ObjectType)
      return Error(json::errc::ParseError, ERROR_LOCATION);

   // extract the chunk definitions
   json::Array chunkDefs;
   error = json::readObject(defContents.get_obj(), kChunkDefs, &chunkDefs);
   if (error)
      return error;

   // return to caller
   *pDefs = chunkDefs;
   return Success();
}

Error initialize()
{
   using boost::bind;
   using namespace module_context;

   source_database::events().onDocRenamed.connect(onDocRenamed);
   source_database::events().onDocRemoved.connect(onDocRemoved);

   ExecBlock initBlock;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "execute_inline_chunk", executeInlineChunk))
      (bind(registerRpcMethod, "refresh_chunk_output", refreshChunkOutput))
      (bind(registerUriHandler, "/" kChunkOutputPath,
            handleChunkOutputRequest))
      (bind(module_context::sourceModuleRFile, "SessionRmdNotebook.R"));

   return initBlock.execute();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<|endoftext|>


<commit_before>/*!
 *  \file File componentAnimationController.cpp
 *  \brief Implementation of componentAnimationController class
 *
 *  The class implemented here is a controller for the animations
 *
 *  \sa componentAnimationController.hpp
 */

#include <componentAnimationController.hpp>
#include <gameObject.hpp>
#include <camera.hpp>
#include <game.hpp>
//#include <inputManager.hpp>

//! A constructor.
  /*!
  This is a constructor method of CompAnimControl class
  */

CompAnimControl::CompAnimControl(string filename, CompCollider* collider) {

  string name = "";
  string animation_filename = "";

  ifstream in(ANIMATION_PATH + filename + ".txt");

  // Checks if the animation's .txt file is already opened
  if (!in.is_open()) {
    cerr << "Erro ao abrir arquivo de grupo de animações '" << filename << "'";
    cerr << endl;
  }
  else {
    in >> name >> animation_filename;
    cur = prev = name;

    animations[name] = make_unique<CompAnim>(animation_filename, collider);

    while (in >> name >> animation_filename) {
      animations[name] = make_unique<CompAnim>(animation_filename, collider);
    }

    in.close();
  }
}

//! A destructor.
  /*!
  This is a destructor method of CompAnimControl class
  */

CompAnimControl::~CompAnimControl() {

}

/*!
  @fn       void CompAnimControl::change_current(string anim, bool rep)
  @brief    Changes current animation
  @param    string anim, bool rep
  @return   void
  @warning  none
*/

void CompAnimControl::change_current(string animation_name,
                            bool repeat_animation) {// repeats animation if true
  // Checks if animation has been found
  if (animations.count(animation_name)) {

    // TODO: add else (do nothing)
    // Checks if current animation is the one to be shown
    if (cur != animation_name) {

      // If true, makes the animation repeat itself
      if (repeat) {
        prev = cur;
      }
      else {
        // Do nothing
      }

      repeat = repeat_animation;
      cur = animation_name;

      get_current().set_current_frame(0);
      get_current().sp.looped = false;
      get_current().own(GO(entity));
    }
    else {
      // Do nothing
    }
  }
  else {
    cerr << "Erro: Controle de animação nao tem animação '";
    cerr << animation_name;
    cerr << "' entity uid = " << entity << endl;
  }
}

/*!
  @fn
  @brief    Returns current animation object
  @param    none
  @return   CompAnim& type animation object pointer
  @warning  none
*/

CompAnim& CompAnimControl::get_current() {
  return *animations[cur];
}

/*!
  @fn       const string& CompAnimControl::get_current_name()const
  @brief    Returns current animation's name as a constant
  @param    none
  @return   const string with animation name
  @warning  none
*/

const string& CompAnimControl::get_current_name()const {
  return cur;
}

/*!
  @fn       string& CompAnimControl::get_current_name()
  @brief    Returns current animation's name
  @param    none
  @return   string with current animation's name
  @warning  none
*/

string& CompAnimControl::get_current_name() {
  return cur;
}

/*!
  @fn       void CompAnimControl::update(float time)
  @brief    Updates the animation according to time
  @param    float value resembling time
  @return   void
  @warning  none
*/

void CompAnimControl::update(float time) {

  // Checks if current animation is in the 'library'
  if (animations.count(cur)) {
    get_current().update(time);

    // Checks if current animation is a looped type or set to repeat
    if (!repeat and get_current().is_looped()) {

      // Defines current frame as 'dead' if Mayumi dies
      if (dying) {
        cur = "dead";
      }
      else {
        get_current().sp.looped = false;
        change_current(prev);

        get_current().update(time);
      }
    }
    else {
      // Do nothing
    }
  }
  else {
    // Do nothing
  }
}

/*!
  @fn       void CompAnimControl::render()
  @brief    Renders current animation
  @param    none
  @return   void
  @warning  none
*/

void CompAnimControl::render() {

  // TODO: else (do nothing)
  // Tries to find the current animation on animations vector, render if found
  if (animations.count(cur)) {
    get_current().render();
  }
  else {
    // Do nothing
  }
}

/*!
  @fn       void CompAnimControl::own(GameObject *go)
  @brief    Sets ownage of animation to a Game Object
  @param    GameObject object
  @return   void
  @warning  none
*/

void CompAnimControl::own(GameObject *game_object) {
  entity = go->uid;

  for (auto &anim:animations) {
    anim.second->own(go);
  }

  get_current().own(go);
}

/*!
  @fn       bool CompAnimControl::kills_component(float time)
  @brief    Method for rendering player's death animation
  @param    float time value
  @return   boolean value
  @warning  TODO: alternative flux in condition structures
*/

bool CompAnimControl::kills_component(float time) { // range: unknown
  UNUSED(time);

  // Checks if die animation isn't in animations
  if (!animations.count("die")) {
    return true;
  }
  else {
    // Do nothing
  }

  // Checks if player is dying
  if (dying) {

    // Makes method return true if current animation isn't player's death
    if (cur != "die") {
      return true;
    }
    else {
      // Do nothing
    }
  }
  else {
    change_current("die", false);
    dying = true;
  }

  return false;
}

/*!
  @fn       Component::type CompAnimControl::get_type()const
  @brief    Returns type of component (or animation) as a constant
  @param    none
  @return   const Component::type
  @warning  none
*/

Component::type CompAnimControl::get_type()const {
  return Component::type::t_animation_control;
}
<commit_msg>[ASSERTS] assertions at componentAnimationsController.cpp<commit_after>/*!
 *  \file File componentAnimationController.cpp
 *  \brief Implementation of componentAnimationController class
 *
 *  The class implemented here is a controller for the animations
 *
 *  \sa componentAnimationController.hpp
 */

#include <componentAnimationController.hpp>
#include <gameObject.hpp>
#include <camera.hpp>
#include <game.hpp>
//#include <inputManager.hpp>

//! A constructor.
  /*!
  This is a constructor method of CompAnimControl class
  */

CompAnimControl::CompAnimControl(string filename, CompCollider* collider) {
  assert(collider != NULL);
  assert(filename != "");

  string name = "";
  string animation_filename = "";

  ifstream in(ANIMATION_PATH + filename + ".txt");

  // Checks if the animation's .txt file is already opened
  if (!in.is_open()) {
    cerr << "Erro ao abrir arquivo de grupo de animações '" << filename << "'";
    cerr << endl;
  }
  else {
    in >> name >> animation_filename;
    cur = prev = name;

    animations[name] = make_unique<CompAnim>(animation_filename, collider);

    while (in >> name >> animation_filename) {
      animations[name] = make_unique<CompAnim>(animation_filename, collider);
    }

    in.close();
  }
}

//! A destructor.
  /*!
  This is a destructor method of CompAnimControl class
  */

CompAnimControl::~CompAnimControl() {

}

/*!
  @fn       void CompAnimControl::change_current(string anim, bool rep)
  @brief    Changes current animation
  @param    string anim, bool rep
  @return   void
  @warning  none
*/

void CompAnimControl::change_current(string animation_name,
                            bool repeat_animation) {// repeats animation if true

  assert(animation_name != "");

  // Checks if animations vector has anything
  if (animations.count(animation_name)) {

    // TODO: add else (do nothing)
    // Checks if current animation is the one to be shown
    if (cur != animation_name) {

      // If true, makes the animation repeat itself
      if (repeat) {
        prev = cur;
      }
      else {
        // Do nothing
      }

      repeat = repeat_animation;
      cur = animation_name;

      get_current().set_current_frame(0);
      get_current().sp.looped = false;
      get_current().own(GO(entity));
    }
    else {
      // Do nothing
    }
  }
  else {
    cerr << "Erro: Controle de animação nao tem animação '";
    cerr << animation_name;
    cerr << "' entity uid = " << entity << endl;
  }
}

/*!
  @fn
  @brief    Returns current animation object
  @param    none
  @return   CompAnim& type animation object pointer
  @warning  none
*/

CompAnim& CompAnimControl::get_current() {
  return *animations[cur];
}

/*!
  @fn       const string& CompAnimControl::get_current_name()const
  @brief    Returns current animation's name as a constant
  @param    none
  @return   const string with animation name
  @warning  none
*/

const string& CompAnimControl::get_current_name()const {
  return cur;
}

/*!
  @fn       string& CompAnimControl::get_current_name()
  @brief    Returns current animation's name
  @param    none
  @return   string with current animation's name
  @warning  none
*/

string& CompAnimControl::get_current_name() {
  return cur;
}

/*!
  @fn       void CompAnimControl::update(float time)
  @brief    Updates the animation according to time
  @param    float value resembling time
  @return   void
  @warning  none
*/

void CompAnimControl::update(float time) {

  // Checks if current animation is in the 'library'
  if (animations.count(cur)) {
    get_current().update(time);

    // Checks if current animation is a looped type or set to repeat
    if (!repeat and get_current().is_looped()) {

      // Defines current frame as 'dead' if Mayumi dies
      if (dying) {
        cur = "dead";
      }
      else {
        get_current().sp.looped = false;
        change_current(prev);

        get_current().update(time);
      }
    }
    else {
      // Do nothing
    }
  }
  else {
    // Do nothing
  }
}

/*!
  @fn       void CompAnimControl::render()
  @brief    Renders current animation
  @param    none
  @return   void
  @warning  none
*/

void CompAnimControl::render() {
  // Tries to find the current animation on animations vector, render if found
  if (animations.count(cur)) {
    get_current().render();
  }
  else {
    // Do nothing
  }
}

/*!
  @fn       void CompAnimControl::own(GameObject *go)
  @brief    Sets ownage of animation to a Game Object
  @param    GameObject object
  @return   void
  @warning  none
*/

void CompAnimControl::own(GameObject *game_object) {
  assert(game_object != NULL);

  entity = go->uid;

  for (auto &anim:animations) {
    anim.second->own(go);
  }

  get_current().own(go);
}

/*!
  @fn       bool CompAnimControl::kills_component(float time)
  @brief    Method for rendering player's death animation
  @param    float time value
  @return   boolean value
  @warning  TODO: alternative flux in condition structures
*/

bool CompAnimControl::kills_component(float time) { // range: unknown
  UNUSED(time);

  // Checks if die animation isn't in animations
  if (!animations.count("die")) {
    return true;
  }
  else {
    // Do nothing
  }

  // Checks if player is dying
  if (dying) {

    // Makes method return true if current animation isn't player's death
    if (cur != "die") {
      return true;
    }
    else {
      // Do nothing
    }
  }
  else {
    change_current("die", false);
    dying = true;
  }

  return false;
}

/*!
  @fn       Component::type CompAnimControl::get_type()const
  @brief    Returns type of component (or animation) as a constant
  @param    none
  @return   const Component::type
  @warning  none
*/

Component::type CompAnimControl::get_type()const {
  return Component::type::t_animation_control;
}
<|endoftext|>