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

#include "lua/program_object.h"

#include <cstdlib>
#include <string>
#include <vector>

#include "base/logging.h"
#include "include/c++/value.h"
#include "lua/ft_lib.h"
#include "lua/global_lock.h"
#include "lua/interpreter_impl.h"
#include "lua/third_party_lua_headers.h"
#include "lua/thread_substitution.h"
#include "util/dump_context.h"

using std::string;
using std::vector;

namespace floating_temple {
namespace lua {

ProgramObject::ProgramObject(const string& file_name,
                             const string& file_content)
    : file_name_(file_name),
      file_content_(file_content) {
}

void ProgramObject::InvokeMethod(Thread* thread,
                                 ObjectReference* object_reference,
                                 const string& method_name,
                                 const vector<Value>& parameters,
                                 Value* return_value) {
  CHECK_EQ(method_name, "run");
  CHECK(return_value != nullptr);

  InterpreterImpl* const interpreter = InterpreterImpl::instance();

  ThreadSubstitution thread_substitution(interpreter, thread);

  lua_State* const lua_state = luaL_newstate();
  CHECK(lua_state != nullptr);

  {
    GlobalLock global_lock(interpreter);

    // Load the standard Lua libraries. (Temporarily suspend garbage collection
    // while the libraries are being loaded.)
    lua_gc(lua_state, LUA_GCSTOP, 0);
    // TODO(dss): Tell the standard libraries to ignore environment variables.
    luaL_openlibs(lua_state);
    InstallFloatingTempleLib(lua_state);
    lua_gc(lua_state, LUA_GCRESTART, 0);

    // Load the content of the source file into the Lua interpreter.
    CHECK_EQ(luaL_loadbuffer(lua_state, file_content_.data(),
                             file_content_.length(), file_name_.c_str()),
             LUA_OK);

    // Run the Lua program.
    CHECK_EQ(lua_pcall(lua_state, 0, 0, 0), LUA_OK);

    lua_close(lua_state);
  }

  // TODO(dss): Print any error message reported by the Lua interpreter.

  // TODO(dss): Return EXIT_FAILURE if an error occurred.
  return_value->set_int64_value(0, EXIT_SUCCESS);
}

void ProgramObject::Dump(DumpContext* dc) const {
  CHECK(dc != nullptr);

  dc->BeginMap();
  dc->AddString("type");
  dc->AddString("ProgramObject");
  dc->End();
}

}  // namespace lua
}  // namespace floating_temple
<commit_msg>When a Lua program fails, write the error message to the debug log.<commit_after>// Floating Temple
// Copyright 2015 Derek S. Snyder
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "lua/program_object.h"

#include <cstdlib>
#include <string>
#include <vector>

#include "base/logging.h"
#include "include/c++/value.h"
#include "lua/ft_lib.h"
#include "lua/global_lock.h"
#include "lua/interpreter_impl.h"
#include "lua/third_party_lua_headers.h"
#include "lua/thread_substitution.h"
#include "util/dump_context.h"

using std::string;
using std::vector;

namespace floating_temple {
namespace lua {

ProgramObject::ProgramObject(const string& file_name,
                             const string& file_content)
    : file_name_(file_name),
      file_content_(file_content) {
}

void ProgramObject::InvokeMethod(Thread* thread,
                                 ObjectReference* object_reference,
                                 const string& method_name,
                                 const vector<Value>& parameters,
                                 Value* return_value) {
  CHECK_EQ(method_name, "run");
  CHECK(return_value != nullptr);

  InterpreterImpl* const interpreter = InterpreterImpl::instance();

  ThreadSubstitution thread_substitution(interpreter, thread);

  lua_State* const lua_state = luaL_newstate();
  CHECK(lua_state != nullptr);

  {
    GlobalLock global_lock(interpreter);

    // Load the standard Lua libraries. (Temporarily suspend garbage collection
    // while the libraries are being loaded.)
    lua_gc(lua_state, LUA_GCSTOP, 0);
    // TODO(dss): Tell the standard libraries to ignore environment variables.
    luaL_openlibs(lua_state);
    InstallFloatingTempleLib(lua_state);
    lua_gc(lua_state, LUA_GCRESTART, 0);

    // Load the content of the source file into the Lua interpreter.
    CHECK_EQ(luaL_loadbuffer(lua_state, file_content_.data(),
                             file_content_.length(), file_name_.c_str()),
             LUA_OK);

    // Run the Lua program.
    CHECK_EQ(lua_pcall(lua_state, 0, 0, 0), LUA_OK)
        << lua_tostring(lua_state, -1);

    lua_close(lua_state);
  }

  // TODO(dss): Print any error message reported by the Lua interpreter.

  // TODO(dss): Return EXIT_FAILURE if an error occurred.
  return_value->set_int64_value(0, EXIT_SUCCESS);
}

void ProgramObject::Dump(DumpContext* dc) const {
  CHECK(dc != nullptr);

  dc->BeginMap();
  dc->AddString("type");
  dc->AddString("ProgramObject");
  dc->End();
}

}  // namespace lua
}  // namespace floating_temple
<|endoftext|>


<commit_before>#include "QLogSink.h"

#include <QAbstractScrollArea>
#include <QScrollBar>

QLogSink::QLogSink( QWidget* parent, flut::log::level level ) :
QPlainTextEdit( parent ),
sink( level ),
enabled_( true )
{
}

void QLogSink::send_log_message( flut::log::level l, const flut::string& msg )
{
	if ( !enabled() )
		return;

	moveCursor( QTextCursor::End );
	QTextCursor cursor( textCursor() );
	QTextCharFormat format;
	format.setFontWeight( QFont::Normal );
	format.setForeground( QBrush( Qt::black ) );

	switch ( l )
	{
	case flut::log::trace_level:
	case flut::log::debug_level:
		format.setForeground( QBrush( Qt::gray ) );
		break;
	case flut::log::info_level:
		format.setForeground( QBrush( Qt::darkBlue ) );
		break;
	case flut::log::warning_level:
		format.setFontWeight( QFont::DemiBold );
		format.setForeground( QBrush( Qt::darkYellow ) );
		break;
	case flut::log::error_level:
	case flut::log::critical_level:
		format.setFontWeight( QFont::DemiBold );
		format.setForeground( QBrush( Qt::darkRed ) );
		break;
	default:
		break;
	}

	cursor.setCharFormat( format );
	cursor.insertText( QString( flut::trim_right_str( msg ).c_str() ) + "\n" );
	verticalScrollBar()->setValue( verticalScrollBar()->maximum() );
}
<commit_msg>QLogSink: added note to make this thread safe<commit_after>#include "QLogSink.h"

#include <QAbstractScrollArea>
#include <QScrollBar>

QLogSink::QLogSink( QWidget* parent, flut::log::level level ) :
QPlainTextEdit( parent ),
sink( level ),
enabled_( true )
{
}

void QLogSink::send_log_message( flut::log::level l, const flut::string& msg )
{
	// TODO: make thread-safe
	if ( !enabled() )
		return;

	moveCursor( QTextCursor::End );
	QTextCursor cursor( textCursor() );
	QTextCharFormat format;
	format.setFontWeight( QFont::Normal );
	format.setForeground( QBrush( Qt::black ) );

	switch ( l )
	{
	case flut::log::trace_level:
	case flut::log::debug_level:
		format.setForeground( QBrush( Qt::gray ) );
		break;
	case flut::log::info_level:
		format.setForeground( QBrush( Qt::darkBlue ) );
		break;
	case flut::log::warning_level:
		format.setFontWeight( QFont::DemiBold );
		format.setForeground( QBrush( Qt::darkYellow ) );
		break;
	case flut::log::error_level:
	case flut::log::critical_level:
		format.setFontWeight( QFont::DemiBold );
		format.setForeground( QBrush( Qt::darkRed ) );
		break;
	default:
		break;
	}

	cursor.setCharFormat( format );
	cursor.insertText( QString( flut::trim_right_str( msg ).c_str() ) + "\n" );
	verticalScrollBar()->setValue( verticalScrollBar()->maximum() );
}
<|endoftext|>


<commit_before>#include "hecl/CVarManager.hpp"
#include "hecl/Console.hpp"
#include <athena/FileWriter.hpp>
#include <athena/Utility.hpp>
#include <hecl/Runtime.hpp>
#include <hecl/hecl.hpp>
#include <algorithm>
#include <memory>
#include <regex>

namespace hecl {

CVar* com_developer = nullptr;
CVar* com_configfile = nullptr;
CVar* com_enableCheats = nullptr;
CVar* com_cubemaps = nullptr;

static const std::regex cmdLineRegex("\\+([\\w\\.]+)=([\\w\\.\\-]+)");
CVarManager* CVarManager::m_instance = nullptr;

static logvisor::Module CVarLog("CVarManager");
CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary)
: m_store(store), m_useBinary(useBinary) {
  m_instance = this;
  com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System);
  com_developer = newCVar("developer", "Enables developer mode", false,
                          (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
  com_enableCheats =
    newCVar("cheats", "Enable cheats", false,
            (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable));
  com_cubemaps =
    newCVar("cubemaps", "Enable cubemaps", false,
            (CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
}

CVarManager::~CVarManager() {}

CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
  std::string tmp(cvar->name());
  athena::utility::tolower(tmp);

  if (m_cvars.find(tmp) != m_cvars.end()) {
    return nullptr;
  }

  CVar* ret = cvar.get();
  m_cvars.insert_or_assign(std::move(tmp), std::move(cvar));
  return ret;
}

CVar* CVarManager::findCVar(std::string_view name) {
  std::string lower(name);
  athena::utility::tolower(lower);
  auto search = m_cvars.find(lower);
  if (search == m_cvars.end())
    return nullptr;

  return search->second.get();
}

std::vector<CVar*> CVarManager::archivedCVars() const {
  std::vector<CVar*> ret;
  for (const auto& pair : m_cvars)
    if (pair.second->isArchive())
      ret.push_back(pair.second.get());

  return ret;
}

std::vector<CVar*> CVarManager::cvars(CVar::EFlags filter) const {
  std::vector<CVar*> ret;
  for (const auto& pair : m_cvars)
    if (filter == CVar::EFlags::None || (pair.second->flags() & filter) != 0)
      ret.push_back(pair.second.get());

  return ret;
}

void CVarManager::deserialize(CVar* cvar) {
  if (!cvar)
    return;

  /* First let's check for a deferred value */
  std::string lowName = cvar->name().data();
  athena::utility::tolower(lowName);
  if (m_deferedCVars.find(lowName) != m_deferedCVars.end()) {
    std::string val = m_deferedCVars[lowName];
    m_deferedCVars.erase(lowName);
    if (cvar->fromLiteralToType(val))
      return;
  }

  /* We were either unable to find a deferred value or got an invalid value */
  if (!cvar->isArchive() && !cvar->isInternalArchivable())
    return;

#if _WIN32
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif
  hecl::Sstat st;

  if (m_useBinary) {
    CVarContainer container;
    filename += _SYS_STR(".bin");
    if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
      return;
    athena::io::FileReader reader(filename);
    if (reader.isOpen())
      container.read(reader);

    if (container.cvars.size() > 0) {
      auto serialized = std::find_if(container.cvars.begin(), container.cvars.end(),
                                     [&cvar](const DNACVAR::CVar& c) { return c.m_name == cvar->name(); });

      if (serialized != container.cvars.end()) {
        DNACVAR::CVar& tmp = *serialized;

        if (cvar->m_value != tmp.m_value) {
          cvar->unlock();
          cvar->fromLiteralToType(tmp.m_value, true);
          cvar->m_wasDeserialized = true;
          cvar->lock();
        }
      }
    }
  } else {
    filename += _SYS_STR(".yaml");
    if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
      return;
    athena::io::FileReader reader(filename);
    if (reader.isOpen()) {
      athena::io::YAMLDocReader docReader;
      if (docReader.parse(&reader)) {
        std::unique_ptr<athena::io::YAMLNode> root = docReader.releaseRootNode();
        auto serialized = std::find_if(root->m_mapChildren.begin(), root->m_mapChildren.end(),
                                       [&cvar](const auto& c) { return c.first == cvar->name(); });

        if (serialized != root->m_mapChildren.end()) {
          const std::unique_ptr<athena::io::YAMLNode>& tmp = serialized->second;

          if (cvar->m_value != tmp->m_scalarString) {
            cvar->unlock();
            cvar->fromLiteralToType(tmp->m_scalarString, true);
            cvar->m_wasDeserialized = true;
            cvar->lock();
          }
        }
      }
    }
  }
}

void CVarManager::serialize() {
#if _WIN32
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif

  if (m_useBinary) {
    CVarContainer container;
    for (const auto& pair : m_cvars) {
      if (pair.second->isArchive() ||
          (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue())) {
        container.cvars.push_back(*pair.second);
      }
    }
    container.cvarCount = atUint32(container.cvars.size());

    filename += _SYS_STR(".bin");
    athena::io::FileWriter writer(filename);
    if (writer.isOpen())
      container.write(writer);
  } else {
    filename += _SYS_STR(".yaml");

    athena::io::FileReader r(filename);
    athena::io::YAMLDocWriter docWriter(nullptr, r.isOpen() ? &r : nullptr);
    r.close();

    docWriter.setStyle(athena::io::YAMLNodeStyle::Block);
    for (const auto& pair : m_cvars) {
      if (pair.second->isArchive() ||
          (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue())) {
        docWriter.writeString(pair.second->name().data(), pair.second->toLiteral());
      }
    }

    athena::io::FileWriter w(filename);
    if (w.isOpen())
      docWriter.finish(&w);
  }
}

CVarManager* CVarManager::instance() { return m_instance; }

void CVarManager::list(Console* con, const std::vector<std::string>& /*args*/) {
  for (const auto& cvar : m_cvars) {
    if (!cvar.second->isHidden())
      con->report(Console::Level::Info, fmt("{}: {}"), cvar.second->name(), cvar.second->help());
  }
}

void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
  if (args.size() < 2) {
    con->report(Console::Level::Info, fmt("Usage setCvar <cvar> <value>"));
    return;
  }

  std::string cvName = args[0];
  athena::utility::tolower(cvName);
  if (m_cvars.find(cvName) == m_cvars.end()) {
    con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
    return;
  }

  const auto& cv = m_cvars[cvName];
  std::string oldVal = cv->value();
  std::string value = args[1];
  auto it = args.begin() + 2;
  for (; it != args.end(); ++it)
    value += " " + *it;

  /*  Check to make sure we're not redundantly assigning the value */
  if (cv->value() == value)
    return;

  if (!cv->fromLiteralToType(value))
    con->report(Console::Level::Warning, fmt("Unable to set cvar '{}' to value '{}'"), cv->name(), value);
  else
    con->report(Console::Level::Info, fmt("Set '{}' from '{}' to '{}'"), cv->name(), oldVal, value);
}

void CVarManager::getCVar(Console* con, const std::vector<std::string>& args) {
  if (args.empty()) {
    con->report(Console::Level::Info, fmt("Usage getCVar <cvar>"));
    return;
  }

  std::string cvName = args[0];
  athena::utility::tolower(cvName);
  if (m_cvars.find(cvName) == m_cvars.end()) {
    con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
    return;
  }

  const auto& cv = m_cvars[cvName];
  con->report(Console::Level::Info, fmt("'{}' = '{}'"), cv->name(), cv->value());
}

void CVarManager::setDeveloperMode(bool v, bool setDeserialized) {
  com_developer->unlock();
  com_developer->fromBoolean(v);
  if (setDeserialized)
    com_developer->m_wasDeserialized = true;
  com_developer->lock();
  com_developer->setModified();
}

void CVarManager::setCheatsEnabled(bool v, bool setDeserialized) {
  com_enableCheats->unlock();
  com_enableCheats->fromBoolean(v);
  if (setDeserialized)
    com_enableCheats->m_wasDeserialized = true;
  com_enableCheats->lock();
  com_enableCheats->setModified();
}

bool CVarManager::restartRequired() const {
  return std::any_of(m_cvars.cbegin(), m_cvars.cend(), [](const auto& entry) {
    return entry.second->isModified() && entry.second->modificationRequiresRestart();
  });
}

void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
  bool oldDeveloper = suppressDeveloper();
  std::string developerName(com_developer->name());
  athena::utility::tolower(developerName);
  for (const SystemString& arg : args) {
    if (arg[0] != _SYS_STR('+')) {
      continue;
    }

    const std::string tmp(SystemUTF8Conv(arg).str());
    std::smatch matches;
    if (!std::regex_match(tmp, matches, cmdLineRegex)) {
      continue;
    }

    std::string cvarName = matches[1].str();
    std::string cvarValue = matches[2].str();
    if (CVar* cv = findCVar(cvarName)) {
      cv->fromLiteralToType(cvarValue);
      athena::utility::tolower(cvarName);
      if (developerName == cvarName)
        /* Make sure we're not overriding developer mode when we restore */
        oldDeveloper = com_developer->toBoolean();
    } else {
      /* Unable to find an existing CVar, let's defer for the time being 8 */
      athena::utility::tolower(cvarName);
      m_deferedCVars.insert_or_assign(std::move(cvarName), std::move(cvarValue));
    }
  }

  restoreDeveloper(oldDeveloper);
}

bool CVarManager::suppressDeveloper() {
  bool oldDeveloper = com_developer->toBoolean();
  CVarUnlocker unlock(com_developer);
  com_developer->fromBoolean(true);

  return oldDeveloper;
}

void CVarManager::restoreDeveloper(bool oldDeveloper) {
  CVarUnlocker unlock(com_developer);
  com_developer->fromBoolean(oldDeveloper);
}

} // namespace hecl
<commit_msg>CVarManager: Eliminate redundant map lookups<commit_after>#include "hecl/CVarManager.hpp"
#include "hecl/Console.hpp"
#include <athena/FileWriter.hpp>
#include <athena/Utility.hpp>
#include <hecl/Runtime.hpp>
#include <hecl/hecl.hpp>
#include <algorithm>
#include <memory>
#include <regex>

namespace hecl {

CVar* com_developer = nullptr;
CVar* com_configfile = nullptr;
CVar* com_enableCheats = nullptr;
CVar* com_cubemaps = nullptr;

static const std::regex cmdLineRegex("\\+([\\w\\.]+)=([\\w\\.\\-]+)");
CVarManager* CVarManager::m_instance = nullptr;

static logvisor::Module CVarLog("CVarManager");
CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary)
: m_store(store), m_useBinary(useBinary) {
  m_instance = this;
  com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System);
  com_developer = newCVar("developer", "Enables developer mode", false,
                          (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
  com_enableCheats = newCVar(
      "cheats", "Enable cheats", false,
      (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable));
  com_cubemaps = newCVar("cubemaps", "Enable cubemaps", false,
                         (CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
}

CVarManager::~CVarManager() {}

CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
  std::string tmp(cvar->name());
  athena::utility::tolower(tmp);

  if (m_cvars.find(tmp) != m_cvars.end()) {
    return nullptr;
  }

  CVar* ret = cvar.get();
  m_cvars.insert_or_assign(std::move(tmp), std::move(cvar));
  return ret;
}

CVar* CVarManager::findCVar(std::string_view name) {
  std::string lower(name);
  athena::utility::tolower(lower);
  auto search = m_cvars.find(lower);
  if (search == m_cvars.end())
    return nullptr;

  return search->second.get();
}

std::vector<CVar*> CVarManager::archivedCVars() const {
  std::vector<CVar*> ret;
  for (const auto& pair : m_cvars)
    if (pair.second->isArchive())
      ret.push_back(pair.second.get());

  return ret;
}

std::vector<CVar*> CVarManager::cvars(CVar::EFlags filter) const {
  std::vector<CVar*> ret;
  for (const auto& pair : m_cvars)
    if (filter == CVar::EFlags::None || (pair.second->flags() & filter) != 0)
      ret.push_back(pair.second.get());

  return ret;
}

void CVarManager::deserialize(CVar* cvar) {
  if (!cvar)
    return;

  /* First let's check for a deferred value */
  std::string lowName = cvar->name().data();
  athena::utility::tolower(lowName);
  if (const auto iter = m_deferedCVars.find(lowName); iter != m_deferedCVars.end()) {
    std::string val = std::move(iter->second);
    m_deferedCVars.erase(lowName);
    if (cvar->fromLiteralToType(val))
      return;
  }

  /* We were either unable to find a deferred value or got an invalid value */
  if (!cvar->isArchive() && !cvar->isInternalArchivable())
    return;

#if _WIN32
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif
  hecl::Sstat st;

  if (m_useBinary) {
    CVarContainer container;
    filename += _SYS_STR(".bin");
    if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
      return;
    athena::io::FileReader reader(filename);
    if (reader.isOpen())
      container.read(reader);

    if (container.cvars.size() > 0) {
      auto serialized = std::find_if(container.cvars.begin(), container.cvars.end(),
                                     [&cvar](const DNACVAR::CVar& c) { return c.m_name == cvar->name(); });

      if (serialized != container.cvars.end()) {
        DNACVAR::CVar& tmp = *serialized;

        if (cvar->m_value != tmp.m_value) {
          cvar->unlock();
          cvar->fromLiteralToType(tmp.m_value, true);
          cvar->m_wasDeserialized = true;
          cvar->lock();
        }
      }
    }
  } else {
    filename += _SYS_STR(".yaml");
    if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
      return;
    athena::io::FileReader reader(filename);
    if (reader.isOpen()) {
      athena::io::YAMLDocReader docReader;
      if (docReader.parse(&reader)) {
        std::unique_ptr<athena::io::YAMLNode> root = docReader.releaseRootNode();
        auto serialized = std::find_if(root->m_mapChildren.begin(), root->m_mapChildren.end(),
                                       [&cvar](const auto& c) { return c.first == cvar->name(); });

        if (serialized != root->m_mapChildren.end()) {
          const std::unique_ptr<athena::io::YAMLNode>& tmp = serialized->second;

          if (cvar->m_value != tmp->m_scalarString) {
            cvar->unlock();
            cvar->fromLiteralToType(tmp->m_scalarString, true);
            cvar->m_wasDeserialized = true;
            cvar->lock();
          }
        }
      }
    }
  }
}

void CVarManager::serialize() {
#if _WIN32
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
  hecl::SystemString filename =
      hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif

  if (m_useBinary) {
    CVarContainer container;
    for (const auto& pair : m_cvars) {
      if (pair.second->isArchive() ||
          (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue())) {
        container.cvars.push_back(*pair.second);
      }
    }
    container.cvarCount = atUint32(container.cvars.size());

    filename += _SYS_STR(".bin");
    athena::io::FileWriter writer(filename);
    if (writer.isOpen())
      container.write(writer);
  } else {
    filename += _SYS_STR(".yaml");

    athena::io::FileReader r(filename);
    athena::io::YAMLDocWriter docWriter(nullptr, r.isOpen() ? &r : nullptr);
    r.close();

    docWriter.setStyle(athena::io::YAMLNodeStyle::Block);
    for (const auto& pair : m_cvars) {
      if (pair.second->isArchive() ||
          (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue())) {
        docWriter.writeString(pair.second->name().data(), pair.second->toLiteral());
      }
    }

    athena::io::FileWriter w(filename);
    if (w.isOpen())
      docWriter.finish(&w);
  }
}

CVarManager* CVarManager::instance() { return m_instance; }

void CVarManager::list(Console* con, const std::vector<std::string>& /*args*/) {
  for (const auto& cvar : m_cvars) {
    if (!cvar.second->isHidden())
      con->report(Console::Level::Info, fmt("{}: {}"), cvar.second->name(), cvar.second->help());
  }
}

void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
  if (args.size() < 2) {
    con->report(Console::Level::Info, fmt("Usage setCvar <cvar> <value>"));
    return;
  }

  std::string cvName = args[0];
  athena::utility::tolower(cvName);
  const auto iter = m_cvars.find(cvName);
  if (iter == m_cvars.end()) {
    con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
    return;
  }

  const auto& cv = iter->second;
  std::string oldVal = cv->value();
  std::string value = args[1];
  auto it = args.begin() + 2;
  for (; it != args.end(); ++it)
    value += " " + *it;

  /*  Check to make sure we're not redundantly assigning the value */
  if (cv->value() == value)
    return;

  if (!cv->fromLiteralToType(value))
    con->report(Console::Level::Warning, fmt("Unable to set cvar '{}' to value '{}'"), cv->name(), value);
  else
    con->report(Console::Level::Info, fmt("Set '{}' from '{}' to '{}'"), cv->name(), oldVal, value);
}

void CVarManager::getCVar(Console* con, const std::vector<std::string>& args) {
  if (args.empty()) {
    con->report(Console::Level::Info, fmt("Usage getCVar <cvar>"));
    return;
  }

  std::string cvName = args[0];
  athena::utility::tolower(cvName);
  const auto iter = m_cvars.find(cvName);
  if (iter == m_cvars.end()) {
    con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
    return;
  }

  const auto& cv = iter->second;
  con->report(Console::Level::Info, fmt("'{}' = '{}'"), cv->name(), cv->value());
}

void CVarManager::setDeveloperMode(bool v, bool setDeserialized) {
  com_developer->unlock();
  com_developer->fromBoolean(v);
  if (setDeserialized)
    com_developer->m_wasDeserialized = true;
  com_developer->lock();
  com_developer->setModified();
}

void CVarManager::setCheatsEnabled(bool v, bool setDeserialized) {
  com_enableCheats->unlock();
  com_enableCheats->fromBoolean(v);
  if (setDeserialized)
    com_enableCheats->m_wasDeserialized = true;
  com_enableCheats->lock();
  com_enableCheats->setModified();
}

bool CVarManager::restartRequired() const {
  return std::any_of(m_cvars.cbegin(), m_cvars.cend(), [](const auto& entry) {
    return entry.second->isModified() && entry.second->modificationRequiresRestart();
  });
}

void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
  bool oldDeveloper = suppressDeveloper();
  std::string developerName(com_developer->name());
  athena::utility::tolower(developerName);
  for (const SystemString& arg : args) {
    if (arg[0] != _SYS_STR('+')) {
      continue;
    }

    const std::string tmp(SystemUTF8Conv(arg).str());
    std::smatch matches;
    if (!std::regex_match(tmp, matches, cmdLineRegex)) {
      continue;
    }

    std::string cvarName = matches[1].str();
    std::string cvarValue = matches[2].str();
    if (CVar* cv = findCVar(cvarName)) {
      cv->fromLiteralToType(cvarValue);
      athena::utility::tolower(cvarName);
      if (developerName == cvarName)
        /* Make sure we're not overriding developer mode when we restore */
        oldDeveloper = com_developer->toBoolean();
    } else {
      /* Unable to find an existing CVar, let's defer for the time being 8 */
      athena::utility::tolower(cvarName);
      m_deferedCVars.insert_or_assign(std::move(cvarName), std::move(cvarValue));
    }
  }

  restoreDeveloper(oldDeveloper);
}

bool CVarManager::suppressDeveloper() {
  bool oldDeveloper = com_developer->toBoolean();
  CVarUnlocker unlock(com_developer);
  com_developer->fromBoolean(true);

  return oldDeveloper;
}

void CVarManager::restoreDeveloper(bool oldDeveloper) {
  CVarUnlocker unlock(com_developer);
  com_developer->fromBoolean(oldDeveloper);
}

} // namespace hecl
<|endoftext|>


<commit_before>//__________________________________________________________________________
// Author(s): Claudio Pizzolato, Monica Reggiani - September 2013
// email:  claudio.pizzolato@griffithuni.edu.au
//         monica.reggiani@gmail.com
//
// DO NOT REDISTRIBUTE WITHOUT PERMISSION
//__________________________________________________________________________
//

#include "Curve.h"
#include <iostream>
#include <vector>
using std::vector;

#include <algorithm>

//const static int pointsNumber = 17;
template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>::Curve() {
  // make a local copy of the points
  x_.clear();
  y_.clear();
  b_.resize(0);
  c_.resize(0);
  d_.resize(0);

}

/* CALC_SPLINE_COEEFICIENTS: this routine takes an array of x and y values,
* and computes the coefficients of natural splines which interpolate the data.
* The code is translated from a Fortran version printed in "Computer
* Methods for Mathematical Computations" by Forsythe, Malcolm, and
* Moler, pp 77-8.
*/

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>::Curve(const vector<double>& x, const vector<double> &y) {

  x_ = x;
  y_ = y;

  computeCoefficients(Int2Type<T>());
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>::Curve(const Curve<mode, T>& orig) {
  x_ = orig.x_;
  y_ = orig.y_;
  b_ = orig.b_;
  c_ = orig.c_;
  d_ = orig.d_;
};

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>& Curve<mode, T>::operator=(const Curve<mode, T>& orig) {
  x_ = orig.x_;
  y_ = orig.y_;
  b_ = orig.b_;
  c_ = orig.c_;
  d_ = orig.d_;
  return *this;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::reset() {

  x_.clear();
  y_.clear();
  b_.resize(0);
  c_.resize(0);
  d_.resize(0);
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::resetPointsWith(const vector<double>& x, const vector<double> &y) {
  // make a local copy of the points
  x_ = x;
  y_ = y;

  computeCoefficients(Int2Type<T>());
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::removeLastPoint()
{
  x_.pop_back();
  y_.pop_back();

  computeCoefficients(Int2Type<T>());
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::removeLastPointNoUpdate() {

    x_.pop_back();
    y_.pop_back();

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
bool Curve<mode, T>::addPoint(double x, double y)  {

  if(x_.empty() || x>x_.back())
  {
      x_.push_back(x);
      y_.push_back(y);

      computeCoefficients(Int2Type<T>());
      return true;
  }
  else return false;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
bool Curve<mode, T>::addPointOnly(double x, double y)
{
  if(x_.empty() || x>x_.back())
  {
      x_.push_back(x);
      y_.push_back(y);
      return true;
  }
  else return false;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::refresh()
{
  computeCoefficients(Int2Type<T>());
}

 template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::computeCoefficients(Int2Type<CurveMode::Linear>) {

    unsigned n = x_.size();
    b_.resize(n);

    if (n > 2) {
        for(unsigned k = 0; k < n-1; ++k)
            b_.at(k) = (y_.at(k) - y_.at(k-1))/(x_.at(k) - x_.at(k-1));
        b_.at(n-1) = b_.at(n-2);
    }
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::computeCoefficients(Int2Type<CurveMode::Cubic>) {

  unsigned n = x_.size();
  int nm1 = n-1;

  b_.resize(n);
  c_.resize(n);
  d_.resize(n);

  if (n > 2) {
    // setup tridiagonal system:
    // b_ = diagonal
    // d_ = offdiagonal
    // c_ = right-hand side
	  d_.at(0) = x_.at(1) - x_.at(0);
	  c_.at(1) = ( y_.at(1) - y_.at(0) ) / d_.at(0);

	  for (unsigned i = 1; i < nm1; ++i ) {
	    d_.at(i) = x_.at(i+1) - x_.at(i);
		  b_.at(i) = 2.0*(d_.at(i-1) + d_.at(i));
		  c_.at(i+1) = (y_.at(i+1) - y_.at(i))/ d_.at(i);
		  c_.at(i) = c_.at(i+1) - c_.at(i);
	  }

	  // End conditions. Third derivatives at x_.at(0) and x_.at(n-1)
	  // are obtained from divided differences.

	  b_.at(0)   = -d_.at(0);
	  b_.at(nm1) = -d_.at(nm1-1);
	  c_.at(0)   = 0.;
	  c_.at(nm1) = 0.;

	  if (n > 3) {
	    c_.at(0) = c_.at(2) / ( x_.at(3)-x_.at(1) ) - c_.at(1) / ( x_.at(2)- x_.at(0) );
		  c_.at(nm1) = c_.at(nm1-1)/(x_.at(nm1)-x_.at(n-3)) -
			             c_.at(n-3)/( x_.at(nm1-1) - x_.at(n-4));
		  c_.at(0) = c_.at(0) * d_.at(0) * d_.at(0) / ( x_.at(3) - x_.at(0) );
		  c_.at(nm1) = -c_.at(nm1) * d_.at(nm1-1) * d_.at(nm1-1)/(x_.at(nm1) - x_.at(n-4));
	  }

	  // Forward elimination
	  for (unsigned i=1; i < n; ++i) {
		  double t = d_.at(i-1)/b_.at(i-1);
		  b_.at(i) -= t * d_.at(i-1);
		  c_.at(i) -= t * c_.at(i-1);
	  }

	  // Back substitution
	  c_.at(nm1) /= b_.at(nm1);
	  for (int j=0; j<nm1; ++j) {
		  int i = nm1 - 1 - j;
		  c_.at(i) = (c_.at(i) - d_.at(i) * c_.at(i+1))/b_.at(i);
	  }

	  // compute polynomial coefficients
	  b_.at(nm1) = (y_.at(nm1) - y_.at(nm1-1))/ d_.at(nm1-1) +
		             d_.at(nm1-1) * (c_.at(nm1-1) + 2.0* c_.at(nm1));

	  for (int i = 0; i < nm1; ++i) {
		  b_.at(i) = (y_.at(i+1) - y_.at(i)) / d_.at(i) - d_.at(i) * ( c_.at(i+1) + 2.0 * c_.at(i) );
		  d_.at(i) = (c_.at(i+1) - c_.at(i)) / d_.at(i);
		  c_.at(i) *= 3.0;
	  }

	  c_.at(nm1) *= 3.0;
	  d_.at(nm1) = d_.at(nm1-1);

  }

  if (n == 2) {
    b_.at(0) = ( y_.at(1)-y_.at(0) ) / ( x_.at(1)-x_.at(0) );
    b_.at(1) = b_.at(0);
    c_.at(0) = 0.;
    c_.at(1) = 0.;
    d_.at(0) = 0.;
    d_.at(1) = 0.;
  }

   // do nothing if size < 2

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
unsigned Curve<mode, T>::getAbscissaPoint(double xValue) const{

  /*  const unsigned n = x_.size();
    unsigned k = 0;
    if (n == 2)
        k = 0;
    else {  // Do a binary search to find which two spline control points the abscissa is between

        unsigned i = 0;
        unsigned j = n;
        while (1) {

            k = (i+j)/2;
            if (xValue < x_.at(k))
                j = k;
            else if (xValue > x_.at(k+1))
                i = k;
            else
                break;
        }
    }
    return k;*/

    const unsigned n = x_.size();
    unsigned k = 0;
    if (n == 2)
        k = 0;
    else k = (std::distance(x_.begin(), std::lower_bound(x_.begin(), x_.end(), xValue)) - 1);

  //  std::cout << "k, k1 "<< k << " " <<k1 << std::endl;

    return k;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getValue(double xValue) const {

    unsigned n = x_.size();
    double yValue(.0);
    if ( xValue < x_.at(0))
        yValue = y_.at(0);
    else if ( xValue > x_.at(n-1))
        yValue = y_.at(n-1);
    else if (n == 1)
        yValue = x_.at(0);
    else
        yValue = getValue(xValue, getAbscissaPoint(xValue), Int2Type<T>());

    return yValue;
}

/*******************************************************************************/
/* INTERPOLATE_SPLINE: given a spline function and an x-value, this routine
* finds the corresponding y-value by interpolating the spline. It
* can return the zeroth, first, or second derivative of the spline
* at that x-value.
*/
template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getValue(double xalue, unsigned abscissaPoint, Int2Type<CurveMode::Cubic>) const {

    const unsigned k(abscissaPoint);
    double dx = xalue - x_.at(k);
    double result(y_.at(k) + dx * ( b_.at(k) + dx * ( c_.at(k) + dx * d_.at(k) ) ) );
    return result;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getValue(double xalue, unsigned abscissaPoint, Int2Type<CurveMode::Linear>) const {

    const unsigned k(abscissaPoint);
    double dx = xalue - x_.at(k);
    return b_.at(k)*dx;

}

/*******************************************************************************/
/* INTERPOLATE_SPLINE: given a spline function and an x-value, this routine

* finds the corresponding y-value by interpolating the spline. It
* can return the zeroth, first, or second derivative of the spline
* at that x-value.
*/

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getFirstDerivative(double xalue) const  {

	int n = x_.size();

        if (n < 1)
            return 0;

	// Now see if the abscissa is out of range of the function

	if ( xalue < x_.at(0))
	  return b_.at(0);

	if ( xalue > x_.at(n-1))
	  return b_.at(n-1);

  if (n == 1)
    return 0;

	int k = 0;
  if (n == 2)
    k = 0;
  else {
	  // Do a binary search to find which two spline control points the abscissa
	  // is between

	  int i = 0;
	  int j = n;

	  while (1)
	  {
		  k = (i+j)/2;
		  if (xalue < x_.at(k))
			  j = k;
		  else if (xalue > x_.at(k+1))
			  i = k;
		  else
			  break;
	  }
	}
	double dx = xalue - x_.at(k);
	return (b_.at(k) + dx * ( 2.0 * c_.at(k) + 3.0 * dx * d_.at(k)));

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getSecondDerivative(double xValue) const  {

    int n = x_.size();

    // Now see if the abscissa is out of range of the function

    if ( xValue < x_.at(0))
      return b_.at(0);

    if ( xValue > x_.at(n-1))
      return b_.at(n-1);

  if (n == 1)
    return 0;

    int k = 0;
  if (n == 2)
    k = 0;
  else {
      // Do a binary search to find which two spline control points the abscissa
      // is between

      int i = 0;
      int j = n;

      while (1)
      {
          k = (i+j)/2;
          if (xValue < x_.at(k))
              j = k;
          else if (xValue > x_.at(k+1))
              i = k;
          else
              break;
      }
    }
    double dx = xValue - x_.at(k);
    return ( 2.0 * c_.at(k) + 6.0 * dx * d_.at(k) );

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
std::ostream& operator<< (std::ostream& output, const Curve<mode, T>& c)
{
    for(unsigned i = 0; i < c.x_.size(); ++i)
        output << c.x_.at(i) << " ";
    output << std::endl;
    for(unsigned i = 0; i < c.y_.size(); ++i)
        output << c.y_.at(i) << " ";
    output << std::endl;
    for (std::vector<double>::const_iterator it = c.b_.begin(); it < c.b_.end(); ++it)
        output << *it << " ";
    output << std::endl;
    for (std::vector<double>::const_iterator it = c.c_.begin(); it < c.c_.end(); ++it)
        output << *it << " ";
    output << std::endl;
    for (std::vector<double>::const_iterator it = c.d_.begin(); it < c.d_.end(); ++it)
        output << *it << " ";
    output << std::endl;
    return output;
}

<commit_msg>Fix linear-interpolation curve<commit_after>//__________________________________________________________________________
// Author(s): Claudio Pizzolato, Monica Reggiani - September 2013
// email:  claudio.pizzolato@griffithuni.edu.au
//         monica.reggiani@gmail.com
//
// DO NOT REDISTRIBUTE WITHOUT PERMISSION
//__________________________________________________________________________
//

#include "Curve.h"
#include <iostream>
#include <vector>
using std::vector;

#include <algorithm>

//const static int pointsNumber = 17;
template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>::Curve() {
  // make a local copy of the points
  x_.clear();
  y_.clear();
  b_.resize(0);
  c_.resize(0);
  d_.resize(0);

}

/* CALC_SPLINE_COEEFICIENTS: this routine takes an array of x and y values,
* and computes the coefficients of natural splines which interpolate the data.
* The code is translated from a Fortran version printed in "Computer
* Methods for Mathematical Computations" by Forsythe, Malcolm, and
* Moler, pp 77-8.
*/

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>::Curve(const vector<double>& x, const vector<double> &y) {

  x_ = x;
  y_ = y;

  computeCoefficients(Int2Type<T>());
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>::Curve(const Curve<mode, T>& orig) {
  x_ = orig.x_;
  y_ = orig.y_;
  b_ = orig.b_;
  c_ = orig.c_;
  d_ = orig.d_;
};

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
Curve<mode, T>& Curve<mode, T>::operator=(const Curve<mode, T>& orig) {
  x_ = orig.x_;
  y_ = orig.y_;
  b_ = orig.b_;
  c_ = orig.c_;
  d_ = orig.d_;
  return *this;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::reset() {

  x_.clear();
  y_.clear();
  b_.resize(0);
  c_.resize(0);
  d_.resize(0);
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::resetPointsWith(const vector<double>& x, const vector<double> &y) {
  // make a local copy of the points
  x_ = x;
  y_ = y;

  computeCoefficients(Int2Type<T>());
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::removeLastPoint()
{
  x_.pop_back();
  y_.pop_back();

  computeCoefficients(Int2Type<T>());
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::removeLastPointNoUpdate() {

    x_.pop_back();
    y_.pop_back();

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
bool Curve<mode, T>::addPoint(double x, double y)  {

  if(x_.empty() || x>x_.back())
  {
      x_.push_back(x);
      y_.push_back(y);

      computeCoefficients(Int2Type<T>());
      return true;
  }
  else return false;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
bool Curve<mode, T>::addPointOnly(double x, double y)
{
  if(x_.empty() || x>x_.back())
  {
      x_.push_back(x);
      y_.push_back(y);
      return true;
  }
  else return false;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::refresh()
{
  computeCoefficients(Int2Type<T>());
}

 template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::computeCoefficients(Int2Type<CurveMode::Linear>) {

    unsigned n = x_.size();
    b_.resize(n);
    c_.resize(n, 0.0);
    d_.resize(n, 0.0);

    if (n >= 2) {
        for(unsigned k = 0; k < n-1; ++k)
            b_.at(k) = (y_.at(k+1) - y_.at(k))/(x_.at(k+1) - x_.at(k));
        b_.at(n-1) = b_.at(n-2);
    }
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
void Curve<mode, T>::computeCoefficients(Int2Type<CurveMode::Cubic>) {

  unsigned n = x_.size();
  int nm1 = n-1;

  b_.resize(n);
  c_.resize(n);
  d_.resize(n);

  if (n > 2) {
    // setup tridiagonal system:
    // b_ = diagonal
    // d_ = offdiagonal
    // c_ = right-hand side
	  d_.at(0) = x_.at(1) - x_.at(0);
	  c_.at(1) = ( y_.at(1) - y_.at(0) ) / d_.at(0);

	  for (unsigned i = 1; i < nm1; ++i ) {
	    d_.at(i) = x_.at(i+1) - x_.at(i);
		  b_.at(i) = 2.0*(d_.at(i-1) + d_.at(i));
		  c_.at(i+1) = (y_.at(i+1) - y_.at(i))/ d_.at(i);
		  c_.at(i) = c_.at(i+1) - c_.at(i);
	  }

	  // End conditions. Third derivatives at x_.at(0) and x_.at(n-1)
	  // are obtained from divided differences.

	  b_.at(0)   = -d_.at(0);
	  b_.at(nm1) = -d_.at(nm1-1);
	  c_.at(0)   = 0.;
	  c_.at(nm1) = 0.;

	  if (n > 3) {
	    c_.at(0) = c_.at(2) / ( x_.at(3)-x_.at(1) ) - c_.at(1) / ( x_.at(2)- x_.at(0) );
		  c_.at(nm1) = c_.at(nm1-1)/(x_.at(nm1)-x_.at(n-3)) -
			             c_.at(n-3)/( x_.at(nm1-1) - x_.at(n-4));
		  c_.at(0) = c_.at(0) * d_.at(0) * d_.at(0) / ( x_.at(3) - x_.at(0) );
		  c_.at(nm1) = -c_.at(nm1) * d_.at(nm1-1) * d_.at(nm1-1)/(x_.at(nm1) - x_.at(n-4));
	  }

	  // Forward elimination
	  for (unsigned i=1; i < n; ++i) {
		  double t = d_.at(i-1)/b_.at(i-1);
		  b_.at(i) -= t * d_.at(i-1);
		  c_.at(i) -= t * c_.at(i-1);
	  }

	  // Back substitution
	  c_.at(nm1) /= b_.at(nm1);
	  for (int j=0; j<nm1; ++j) {
		  int i = nm1 - 1 - j;
		  c_.at(i) = (c_.at(i) - d_.at(i) * c_.at(i+1))/b_.at(i);
	  }

	  // compute polynomial coefficients
	  b_.at(nm1) = (y_.at(nm1) - y_.at(nm1-1))/ d_.at(nm1-1) +
		             d_.at(nm1-1) * (c_.at(nm1-1) + 2.0* c_.at(nm1));

	  for (int i = 0; i < nm1; ++i) {
		  b_.at(i) = (y_.at(i+1) - y_.at(i)) / d_.at(i) - d_.at(i) * ( c_.at(i+1) + 2.0 * c_.at(i) );
		  d_.at(i) = (c_.at(i+1) - c_.at(i)) / d_.at(i);
		  c_.at(i) *= 3.0;
	  }

	  c_.at(nm1) *= 3.0;
	  d_.at(nm1) = d_.at(nm1-1);

  }

  if (n == 2) {
    b_.at(0) = ( y_.at(1)-y_.at(0) ) / ( x_.at(1)-x_.at(0) );
    b_.at(1) = b_.at(0);
    c_.at(0) = 0.;
    c_.at(1) = 0.;
    d_.at(0) = 0.;
    d_.at(1) = 0.;
  }

   // do nothing if size < 2

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
unsigned Curve<mode, T>::getAbscissaPoint(double xValue) const{

  /*  const unsigned n = x_.size();
    unsigned k = 0;
    if (n == 2)
        k = 0;
    else {  // Do a binary search to find which two spline control points the abscissa is between

        unsigned i = 0;
        unsigned j = n;
        while (1) {

            k = (i+j)/2;
            if (xValue < x_.at(k))
                j = k;
            else if (xValue > x_.at(k+1))
                i = k;
            else
                break;
        }
    }
    return k;*/

    const unsigned n = x_.size();
    unsigned k = 0;
    if (n == 2)
        k = 0;
    else k = (std::distance(x_.begin(), std::lower_bound(x_.begin(), x_.end(), xValue)) - 1);

  //  std::cout << "k, k1 "<< k << " " <<k1 << std::endl;

    return k;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getValue(double xValue) const {

    unsigned n = x_.size();
    double yValue(.0);
    if ( xValue < x_.at(0))
        yValue = y_.at(0);
    else if ( xValue > x_.at(n-1))
        yValue = y_.at(n-1);
    else if (n == 1)
        yValue = x_.at(0);
    else
        yValue = getValue(xValue, getAbscissaPoint(xValue), Int2Type<T>());

    return yValue;
}

/*******************************************************************************/
/* INTERPOLATE_SPLINE: given a spline function and an x-value, this routine
* finds the corresponding y-value by interpolating the spline. It
* can return the zeroth, first, or second derivative of the spline
* at that x-value.
*/
template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getValue(double xalue, unsigned abscissaPoint, Int2Type<CurveMode::Cubic>) const {

    const unsigned k(abscissaPoint);
    double dx = xalue - x_.at(k);
    double result(y_.at(k) + dx * ( b_.at(k) + dx * ( c_.at(k) + dx * d_.at(k) ) ) );
    return result;
}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getValue(double xalue, unsigned abscissaPoint, Int2Type<CurveMode::Linear>) const {

    const unsigned k(abscissaPoint);
    double dx = xalue - x_.at(k);
    return b_.at(k)*dx;

}

/*******************************************************************************/
/* INTERPOLATE_SPLINE: given a spline function and an x-value, this routine

* finds the corresponding y-value by interpolating the spline. It
* can return the zeroth, first, or second derivative of the spline
* at that x-value.
*/

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getFirstDerivative(double xalue) const  {

	int n = x_.size();

        if (n < 1)
            return 0;

	// Now see if the abscissa is out of range of the function

	if ( xalue < x_.at(0))
	  return b_.at(0);

	if ( xalue > x_.at(n-1))
	  return b_.at(n-1);

  if (n == 1)
    return 0;

	int k = 0;
  if (n == 2)
    k = 0;
  else {
	  // Do a binary search to find which two spline control points the abscissa
	  // is between

	  int i = 0;
	  int j = n;

	  while (1)
	  {
		  k = (i+j)/2;
		  if (xalue < x_.at(k))
			  j = k;
		  else if (xalue > x_.at(k+1))
			  i = k;
		  else
			  break;
	  }
	}
	double dx = xalue - x_.at(k);
	return (b_.at(k) + dx * ( 2.0 * c_.at(k) + 3.0 * dx * d_.at(k)));

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
double Curve<mode, T>::getSecondDerivative(double xValue) const  {

    int n = x_.size();

    // Now see if the abscissa is out of range of the function

    if ( xValue < x_.at(0))
      return b_.at(0);

    if ( xValue > x_.at(n-1))
      return b_.at(n-1);

  if (n == 1)
    return 0;

    int k = 0;
  if (n == 2)
    k = 0;
  else {
      // Do a binary search to find which two spline control points the abscissa
      // is between

      int i = 0;
      int j = n;

      while (1)
      {
          k = (i+j)/2;
          if (xValue < x_.at(k))
              j = k;
          else if (xValue > x_.at(k+1))
              i = k;
          else
              break;
      }
    }
    double dx = xValue - x_.at(k);
    return ( 2.0 * c_.at(k) + 6.0 * dx * d_.at(k) );

}

template <CurveMode::Mode mode,  CurveMode::Interpolation T>
std::ostream& operator<< (std::ostream& output, const Curve<mode, T>& c)
{
    for(unsigned i = 0; i < c.x_.size(); ++i)
        output << c.x_.at(i) << " ";
    output << std::endl;
    for(unsigned i = 0; i < c.y_.size(); ++i)
        output << c.y_.at(i) << " ";
    output << std::endl;
    for (std::vector<double>::const_iterator it = c.b_.begin(); it < c.b_.end(); ++it)
        output << *it << " ";
    output << std::endl;
    for (std::vector<double>::const_iterator it = c.c_.begin(); it < c.c_.end(); ++it)
        output << *it << " ";
    output << std::endl;
    for (std::vector<double>::const_iterator it = c.d_.begin(); it < c.d_.end(); ++it)
        output << *it << " ";
    output << std::endl;
    return output;
}

<|endoftext|>


<commit_before>/*****************************************************************************\

Name:   abs_fixed_probes.cxx
Author: Matthias W. Smith
Email:  mwsmith2@uw.edu

About:  Implements a MIDAS frontend that is aware of the
        multiplexers.  It configures them, takes data in a
        sequence, and builds an event from all the data.

\*****************************************************************************/

//--- std includes ----------------------------------------------------------//
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <iostream>
#include <vector>
#include <array>
#include <cmath>
#include <ctime>
using std::string;

//--- other includes --------------------------------------------------------//
#include "midas.h"
#include "TFile.h"
#include "TTree.h"

//--- project includes ------------------------------------------------------//
#include "g2field/core/field_structs.hh"
#include "g2field/core/field_constants.hh"
#include "fixed_probe_sequencer.hh"
#include "frontend_utils.hh"

//--- globals ---------------------------------------------------------------//
#define FRONTEND_NAME "Abs Fixed Probes"

extern "C" {

  // The frontend name (client name) as seen by other MIDAS clients
  char *frontend_name = (char *)FRONTEND_NAME;

  // The frontend file name, don't change it.
  char *frontend_file_name = (char *)__FILE__;

  // frontend_loop is called periodically if this variable is TRUE
  BOOL frontend_call_loop = FALSE;

  // A frontend status page is displayed with this frequency in ms.
  INT display_period = 1000;

  // maximum event size produced by this frontend
  INT max_event_size = 0x800000; // 8 MB

  // maximum event size for fragmented events (EQ_FRAGMENTED)
  INT max_event_size_frag = 0x100000;

  // buffer size to hold events
  INT event_buffer_size = 0x1000000; // 64 MB

  // Function declarations
  INT frontend_init();
  INT frontend_exit();
  INT begin_of_run(INT run_number, char *error);
  INT end_of_run(INT run_number, char *error);
  INT pause_run(INT run_number, char *error);
  INT resume_run(INT run_number, char *error);

  INT frontend_loop();
  INT read_fixed_probe_event(char *pevent, INT off);
  INT poll_event(INT source, INT count, BOOL test);
  INT interrupt_configure(INT cmd, INT source, POINTER_T adr);

  // Equipment list

  EQUIPMENT equipment[] =
    {
      {FRONTEND_NAME,  // equipment name
       { 18, 13,        // event ID, trigger mask
         "SYSTEM",      // event buffer (use to be SYSTEM)
         EQ_PERIODIC,   // equipment type
         0,             // not used
         "MIDAS",       // format
         TRUE,          // enabled
         RO_RUNNING,    // read only when running
         10,            // poll for 10ms
         0,             // stop run after this event limit
         0,             // number of sub events
         0,             // don't log history
         "", "", "",
       },
       read_fixed_probe_event,      // readout routine
      },

      {""}
    };

} //extern C

RUNINFO runinfo;

// Anonymous namespace for my "globals"
namespace {
double step_size = 0.4;  //  23.375 mm per 1 step size // So pretty close to 1 inch per 1 step_size (note: this calibration occurred using a chord of about 3 meters, so the string was not moving along the azimuth. So there is a missing cos(theta) -- where theta is small -- that needs to be included

double event_rate_limit = 10.0;
int num_steps = 50; // num_steps was 50
int num_shots = 1;
int trigger_count = 0;
int event_number = 0;
bool write_root = false;
bool save_full_waveforms = false;
bool write_midas = true;
bool use_stepper = true;
bool ino_stepper_type = false;

TFile *pf;
TTree *pt_abs;
TTree *pt_full;

std::atomic<bool> run_in_progress;
std::mutex data_mutex;

boost::property_tree::ptree conf;
std::string nmr_sequence_conf_file;

g2field::abs_fixed_t data;
g2field::abs_online_fixed_t full_data;
g2field::FixedProbeSequencer *event_manager = nullptr;

const int nprobes = g2field::kAbsNmrNumFixedProbes;
const char *const mbank_name = (char *)"ACFP";
}

void trigger_loop();
void set_json_tmpfiles();
int load_device_classes();

void set_json_tmpfiles()
{
  // Allocations
  char tmp_file[256];
  std::string conf_file;
  boost::property_tree::ptree pt;
  boost::property_tree::ptree pt_child;

  // Copy the wfd config file.
  snprintf(tmp_file, 128, "/tmp/g2-nmr-config_XXXXXX.json");
  mkstemps(tmp_file, 5);
  conf_file = std::string(tmp_file);

  // Copy the json, and set to the temp file.
  pt = conf.get_child("devices.sis_3302");
  boost::property_tree::write_json(conf_file, pt.get_child("sis_3302_0"));
  pt.clear();
  pt.put("sis_3302_0", conf_file);

  conf.get_child("devices.sis_3302").erase("sis_3302_0");
  conf.put_child("devices.sis_3302", pt);

  // Copy the trigger sequence file.
  snprintf(tmp_file, 128, "/tmp/g2-nmr-config_XXXXXX.json");
  mkstemps(tmp_file, 5);
  conf_file = std::string(tmp_file);

  // Copy the json, and set to the temp file.
  pt = conf.get_child("trg_seq_file");
  conf.erase("trg_seq_file");
  conf.put<std::string>("trg_seq_file", conf_file);
  boost::property_tree::write_json(conf_file, pt);

  // Now the mux configuration
  snprintf(tmp_file, 128, "/tmp/g2-nmr-config_XXXXXX.json");
  mkstemps(tmp_file, 5);
  conf_file = std::string(tmp_file);

  // Copy the json, and set to the temp file.
  pt = conf.get_child("mux_conf_file");
  conf.erase("mux_conf_file");
  conf.put<std::string>("mux_conf_file",  conf_file);
  boost::property_tree::write_json(conf_file, pt);

  // And the fid params.
  snprintf(tmp_file, 128, "/tmp/g2-nmr-config_XXXXXX.json");
  mkstemps(tmp_file, 5);
  conf_file = std::string(tmp_file);

  // Copy the json, and set to the temp file.
  pt = conf.get_child("fid_conf_file");
  conf.erase("fid_conf_file");
  conf.put<std::string>("fid_conf_file", conf_file);
  boost::property_tree::write_json(conf_file, pt);

  // Now save the config to a temp file and feed it to the Event Manager.
  snprintf(tmp_file, 128, "/tmp/g2-nmr-config_XXXXXX.json");
  mkstemps(tmp_file, 5);
  nmr_sequence_conf_file = std::string(tmp_file);
  boost::property_tree::write_json(nmr_sequence_conf_file, conf);
}

int load_device_classes()
{
  // Allocations
  char str[256];
  std::string conf_file;

  // Set up the event mananger.
  if (event_manager == nullptr) {
    event_manager = new g2field::FixedProbeSequencer(nmr_sequence_conf_file,
						     nprobes);
  } else {

    event_manager->EndOfRun();
    delete event_manager;
    event_manager = new g2field::FixedProbeSequencer(nmr_sequence_conf_file,
						     nprobes);
  }

  event_rate_limit = conf.get<double>("event_rate_limit");

  return SUCCESS;
}

//--- Frontend Init ----------------------------------------------------------//
INT frontend_init()
{
  INT rc = load_settings(frontend_name, conf);

  if (rc != SUCCESS) {
    // Error already logged in load_settings.
    return rc;
  }

  set_json_tmpfiles();

  rc = load_device_classes();
  if (rc != SUCCESS) {
    // Error already logged in load_device_classes.
    return rc;
  }

  run_in_progress = false;
  event_manager->BeginOfRun();

  cm_msg(MINFO, "init", "Abs Fixed initialization complete");
  return SUCCESS;
}

//--- Frontend Exit ---------------------------------------------------------//
INT frontend_exit()
{
  run_in_progress = false;

  event_manager->EndOfRun();
  delete event_manager;

  cm_msg(MINFO, "exit", "Abs Fixed teardown complete");
  return SUCCESS;
}

//--- Begin of Run --------------------------------------------------//
INT begin_of_run(INT run_number, char *error)
{
  INT rc = load_settings(frontend_name, conf);

  if (rc != SUCCESS) {
    return rc;
  }

  set_json_tmpfiles();

  rc = load_device_classes();
  if (rc != SUCCESS) {
    return rc;
  }

  event_manager->BeginOfRun();

  // ODB parameters
  HNDLE hDB, hkey;
  char str[256];
  int size;
  BOOL flag;

  // Set up the data.
  std::string datadir;
  std::string filename;

  // Grab the database handle.
  cm_get_experiment_database(&hDB, NULL);

  // Get the run info out of the ODB.
  db_find_key(hDB, 0, "/Runinfo", &hkey);
  if (db_open_record(hDB, hkey, &runinfo, sizeof(runinfo), MODE_READ,
		     NULL, NULL) != DB_SUCCESS) {
    cm_msg(MERROR, "begin_of_run", "Can't open \"/Runinfo\" in ODB");
    return CM_DB_ERROR;
  }

  // Get the data directory from the ODB.
  snprintf(str, sizeof(str), "/Logger/Data dir");
  db_find_key(hDB, 0, str, &hkey);

  if (hkey) {
    size = sizeof(str);
    db_get_data(hDB, hkey, str, &size, TID_STRING);
    datadir = std::string(str);
  }

  // Set the filename
  snprintf(str, sizeof(str), "root/fixed_run_%05d.root", runinfo.run_number);

  // Join the directory and filename using boost filesystem.
  filename = (boost::filesystem::path(datadir) / boost::filesystem::path(str)).string();

  // Get the parameter for root output.
  db_find_key(hDB, 0, "/Experiment/Run Parameters/Root Output", &hkey);

  if (hkey) {
    size = sizeof(flag);
    db_get_data(hDB, hkey, &flag, &size, TID_BOOL);

    write_root = flag;
    write_root = true;
  }

  // Check if we want to save full waveforms.
  if (write_root) {

    db_find_key(hDB, 0, "/Experiment/Run Parameters/Save Full Waveforms", &hkey);

    if (hkey) {
      size = sizeof(flag);
      db_get_data(hDB, hkey, &flag, &size, TID_BOOL);

      save_full_waveforms = flag;
    }
  }

  if (write_root) {
    // Set up the ROOT data output.
    pf = new TFile(filename.c_str(), "recreate");
    pt_abs = new TTree("t_acfp", "Abs Fixed Probe Data");
    pt_abs->SetAutoSave(5);
    pt_abs->SetAutoFlush(20);

    std::string br_name("abs_fixed");

    pt_abs->Branch(br_name.c_str(), &data.clock_sys_ns[0], g2field::abs_fixed_str);

    if (save_full_waveforms) {
      std::string br_name("full_abs_fixed");
      pt_full->SetAutoSave(5);
      pt_full->SetAutoFlush(20);

      pt_full->Branch(br_name.c_str(),
                      &full_data.clock_sys_ns[0],
                      g2field::abs_online_fixed_str);
    }
  }

  // HW part
  event_rate_limit = conf.get<double>("event_rate_limit");

  event_number = 0;
  run_in_progress = true;

  cm_msg(MLOG, "begin_of_run", "Completed successfully");

  return SUCCESS;
}

//--- End of Run ----------------------------------------------------*/
INT end_of_run(INT run_number, char *error)
{
  // Make sure we write the ROOT data.
  if (run_in_progress && write_root) {

    pt_abs->Write();

    if (save_full_waveforms) {
      pt_full->Write();
    }

    pf->Write();
    pf->Close();

    delete pf;
  }

  run_in_progress = false;

  cm_msg(MLOG, "end_of_run", "Completed successfully");
  return SUCCESS;
}

//--- Pause Run -----------------------------------------------------*/
INT pause_run(INT run_number, char *error)
{
  event_manager->PauseRun();
  return SUCCESS;
}

//--- Resuem Run ----------------------------------------------------*/
INT resume_run(INT run_number, char *error)
{
  event_manager->ResumeRun();
  return SUCCESS;
}

//--- Frontend Loop -------------------------------------------------*/

INT frontend_loop()
{
  // If frontend_call_loop is true, this routine gets called when
  // the frontend is idle or once between every event
  return SUCCESS;
}

//-------------------------------------------------------------------*/

/********************************************************************\

  Readout routines for different events

\********************************************************************/

//--- Trigger event routines ----------------------------------------*/

INT poll_event(INT source, INT count, BOOL test) {

  static bool triggered = false;

  // fake calibration
  if (test) {
    for (int i = 0; i < count; i++) {
      usleep(10);
    }
    return 0;
  }

  // if (!triggered) {
  //   event_manager->IssueTrigger();
  //   triggered = true;
  // }

  // if (triggered && event_manager->HasEvent()) {

  //   triggered = false;
  //   return 1;

  // } else {

  //   return 0;
  // }
  return 0;
}

//--- Interrupt configuration ---------------------------------------*/

INT interrupt_configure(INT cmd, INT source, PTYPE adr)
{
  switch (cmd) {
  case CMD_INTERRUPT_ENABLE:
    break;
  case CMD_INTERRUPT_DISABLE:
    break;
  case CMD_INTERRUPT_ATTACH:
    break;
  case CMD_INTERRUPT_DETACH:
    break;
  }
  return SUCCESS;
}

//--- Event readout -------------------------------------------------*/

INT read_fixed_probe_event(char *pevent, INT off)
{
  static bool triggered = false;
  static unsigned long long num_events;
  static unsigned long long events_written;

  // Allocate vectors for the FIDs
  static std::vector<double> tm;
  static std::vector<double> wf;

  int count = 0;
  char bk_name[10];
  DWORD *pdata;

  if (!triggered) {
    event_manager->IssueTrigger();
    cm_msg(MDEBUG, "read_fixed_event", "issued trigger");
    triggered = true;
  }

  if (triggered && !event_manager->HasEvent()) {
    return 0;

  } else {

    cm_msg(MDEBUG, "read_fixed_event", "got data");
  }

  auto abs_data = event_manager->GetCurrentEvent();

  if ((abs_data.clock_sys_ns[0] == 0) && (abs_data.clock_sys_ns[nprobes-1] == 0)) {
    event_manager->PopCurrentEvent();
    triggered = false;
    return 0;
  }

  // Set the time vector.
  if (tm.size() == 0) {

    tm.resize(g2field::kNmrFidLengthRecord);
    wf.resize(g2field::kNmrFidLengthRecord);

    for (int n = 0; n < g2field::kNmrFidLengthRecord; ++n) {
      tm[n] = 0.001 * n;
    }
  }

  data_mutex.lock();

  for (int idx = 0; idx < nprobes; ++idx) {

    for (int n = 0; n < g2field::kNmrFidLengthRecord; ++n) {
      wf[n] = abs_data.trace[idx][n*10 + 1]; // Offset avoid spikes in sis3302
      data.trace[idx][n] = wf[n];
    }

    fid::Fid myfid(wf, tm);

    // Make sure we got an FID signal
    if (myfid.isgood()) {

      data.freq[idx] = myfid.CalcPhaseFreq();
      data.ferr[idx] = myfid.freq_err();
      data.fid_snr[idx] = myfid.snr();
      data.fid_len[idx] = myfid.fid_time();

    } else {

      myfid.DiagnosticInfo();
      data.freq[idx] = -1.0;
      data.ferr[idx] = -1.0;
      data.fid_snr[idx] = -1.0;
      data.fid_len[idx] = -1.0;
    }
  }

  cm_msg(MINFO, frontend_name, "copying the data from event");
  std::copy(abs_data.clock_sys_ns.begin(),
            abs_data.clock_sys_ns.begin() + nprobes,
            &data.clock_sys_ns[0]);

  std::copy(abs_data.clock_gps_ns.begin(),
            abs_data.clock_gps_ns.begin() + nprobes,
            &data.clock_gps_ns[0]);

  std::copy(abs_data.device_clock.begin(),
            abs_data.device_clock.begin() + nprobes,
            &data.device_clock[0]);

  std::copy(abs_data.fid_snr.begin(),
            abs_data.fid_snr.begin() + nprobes,
            &data.fid_snr[0]);

  std::copy(abs_data.fid_len.begin(),
            abs_data.fid_len.begin() + nprobes,
            &data.fid_len[0]);

  std::copy(abs_data.freq.begin(),
            abs_data.freq.begin() + nprobes,
            &data.freq[0]);

  std::copy(abs_data.ferr.begin(),
            abs_data.ferr.begin() + nprobes,
            &data.ferr[0]);

  std::copy(abs_data.freq_zc.begin(),
            abs_data.freq_zc.begin() + nprobes,
            &data.freq_zc[0]);

  std::copy(abs_data.ferr_zc.begin(),
            abs_data.ferr_zc.begin() + nprobes,
            &data.ferr_zc[0]);

  std::copy(abs_data.method.begin(),
            abs_data.method.begin() + nprobes,
            &data.method[0]);

  std::copy(abs_data.health.begin(),
            abs_data.health.begin() + nprobes,
            &data.health[0]);

  data_mutex.unlock();

  if (write_root && run_in_progress) {
    cm_msg(MINFO, "read_fixed_event", "Filling TTree");
    // Now that we have a copy of the latest event, fill the tree.
    pt_abs->Fill();

    if (save_full_waveforms) {
      pt_full->Fill();
    }

    num_events++;

    if (num_events % 10 == 1) {

      cm_msg(MINFO, frontend_name, "flushing TTree.");
      pt_abs->AutoSave("SaveSelf,FlushBaskets");

      if (save_full_waveforms) {
        pt_full->AutoSave("SaveSelf,FlushBaskets");
      }

      pf->Flush();
    }
  }

  // And MIDAS output.
  bk_init32(pevent);

  if (write_midas) {

    // Copy the absolute calibration fixed probe data.
    bk_create(pevent, mbank_name, TID_DWORD, &pdata);

    memcpy(pdata, &data, sizeof(data));
    pdata += sizeof(data) / sizeof(DWORD);

    bk_close(pevent, pdata);
  }

  // Pop the event now that we are done copying it.
  cm_msg(MINFO, "read_fixed_event", "Finished with event, popping from queue");
  event_manager->PopCurrentEvent();

  // Let the front-end know we are ready for another trigger.
  triggered = false;

  return bk_size(pevent);
}
<commit_msg>rm abs_fix_<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-present ScyllaDB
 */

/*
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#pragma once

#include "compaction_strategy_impl.hh"
#include "compaction.hh"
#include "sstables/sstables.hh"
#include <boost/algorithm/cxx11/any_of.hpp>

namespace sstables {

class size_tiered_compaction_strategy_options {
    static constexpr uint64_t DEFAULT_MIN_SSTABLE_SIZE = 50L * 1024L * 1024L;
    static constexpr double DEFAULT_BUCKET_LOW = 0.5;
    static constexpr double DEFAULT_BUCKET_HIGH = 1.5;
    static constexpr double DEFAULT_COLD_READS_TO_OMIT = 0.05;
    const sstring MIN_SSTABLE_SIZE_KEY = "min_sstable_size";
    const sstring BUCKET_LOW_KEY = "bucket_low";
    const sstring BUCKET_HIGH_KEY = "bucket_high";
    const sstring COLD_READS_TO_OMIT_KEY = "cold_reads_to_omit";

    uint64_t min_sstable_size = DEFAULT_MIN_SSTABLE_SIZE;
    double bucket_low = DEFAULT_BUCKET_LOW;
    double bucket_high = DEFAULT_BUCKET_HIGH;
    double cold_reads_to_omit =  DEFAULT_COLD_READS_TO_OMIT;
public:
    size_tiered_compaction_strategy_options(const std::map<sstring, sstring>& options);

    size_tiered_compaction_strategy_options();

    // FIXME: convert java code below.
#if 0
    public static Map<String, String> validateOptions(Map<String, String> options, Map<String, String> uncheckedOptions) throws ConfigurationException
    {
        String optionValue = options.get(MIN_SSTABLE_SIZE_KEY);
        try
        {
            long minSSTableSize = optionValue == null ? DEFAULT_MIN_SSTABLE_SIZE : Long.parseLong(optionValue);
            if (minSSTableSize < 0)
            {
                throw new ConfigurationException(String.format("%s must be non negative: %d", MIN_SSTABLE_SIZE_KEY, minSSTableSize));
            }
        }
        catch (NumberFormatException e)
        {
            throw new ConfigurationException(String.format("%s is not a parsable int (base10) for %s", optionValue, MIN_SSTABLE_SIZE_KEY), e);
        }

        double bucketLow = parseDouble(options, BUCKET_LOW_KEY, DEFAULT_BUCKET_LOW);
        double bucketHigh = parseDouble(options, BUCKET_HIGH_KEY, DEFAULT_BUCKET_HIGH);
        if (bucketHigh <= bucketLow)
        {
            throw new ConfigurationException(String.format("%s value (%s) is less than or equal to the %s value (%s)",
                                                           BUCKET_HIGH_KEY, bucketHigh, BUCKET_LOW_KEY, bucketLow));
        }

        double maxColdReadsRatio = parseDouble(options, COLD_READS_TO_OMIT_KEY, DEFAULT_COLD_READS_TO_OMIT);
        if (maxColdReadsRatio < 0.0 || maxColdReadsRatio > 1.0)
        {
            throw new ConfigurationException(String.format("%s value (%s) should be between between 0.0 and 1.0",
                                                           COLD_READS_TO_OMIT_KEY, optionValue));
        }

        uncheckedOptions.remove(MIN_SSTABLE_SIZE_KEY);
        uncheckedOptions.remove(BUCKET_LOW_KEY);
        uncheckedOptions.remove(BUCKET_HIGH_KEY);
        uncheckedOptions.remove(COLD_READS_TO_OMIT_KEY);

        return uncheckedOptions;
    }
#endif
    friend class size_tiered_compaction_strategy;
};

class size_tiered_compaction_strategy : public compaction_strategy_impl {
    size_tiered_compaction_strategy_options _options;
    compaction_backlog_tracker _backlog_tracker;

    // Return a list of pair of shared_sstable and its respective size.
    static std::vector<std::pair<sstables::shared_sstable, uint64_t>> create_sstable_and_length_pairs(const std::vector<sstables::shared_sstable>& sstables);

    // Group files of similar size into buckets.
    static std::vector<std::vector<sstables::shared_sstable>> get_buckets(const std::vector<sstables::shared_sstable>& sstables, size_tiered_compaction_strategy_options options);

    std::vector<std::vector<sstables::shared_sstable>> get_buckets(const std::vector<sstables::shared_sstable>& sstables) const;

    // Maybe return a bucket of sstables to compact
    std::vector<sstables::shared_sstable>
    most_interesting_bucket(std::vector<std::vector<sstables::shared_sstable>> buckets, unsigned min_threshold, unsigned max_threshold);

    // Return the average size of a given list of sstables.
    uint64_t avg_size(std::vector<sstables::shared_sstable> const& sstables) const {
        assert(sstables.size() > 0); // this should never fail
        uint64_t n = 0;

        for (auto const& sstable : sstables) {
            n += sstable->data_size();
        }

        return n / sstables.size();
    }

    bool is_bucket_interesting(const std::vector<sstables::shared_sstable>& bucket, int min_threshold) const {
        return bucket.size() >= size_t(min_threshold);
    }

    bool is_any_bucket_interesting(const std::vector<std::vector<sstables::shared_sstable>>& buckets, int min_threshold) const {
        return boost::algorithm::any_of(buckets, [&] (const auto& bucket) {
            return this->is_bucket_interesting(bucket, min_threshold);
        });
    }
public:
    size_tiered_compaction_strategy() = default;

    size_tiered_compaction_strategy(const std::map<sstring, sstring>& options);
    explicit size_tiered_compaction_strategy(const size_tiered_compaction_strategy_options& options);

    virtual compaction_descriptor get_sstables_for_compaction(table_state& table_s, strategy_control& control, std::vector<sstables::shared_sstable> candidates) override;

    static int64_t estimated_pending_compactions(const std::vector<sstables::shared_sstable>& sstables,
        int min_threshold, int max_threshold, size_tiered_compaction_strategy_options options);
    virtual int64_t estimated_pending_compactions(table_state& table_s) const override;

    virtual compaction_strategy_type type() const override {
        return compaction_strategy_type::size_tiered;
    }

    // Return the most interesting bucket for a set of sstables
    static std::vector<sstables::shared_sstable>
    most_interesting_bucket(const std::vector<sstables::shared_sstable>& candidates, int min_threshold, int max_threshold,
        size_tiered_compaction_strategy_options options = {});

    virtual compaction_backlog_tracker& get_backlog_tracker() override {
        return _backlog_tracker;
    }

    virtual compaction_descriptor get_reshaping_job(std::vector<shared_sstable> input, schema_ptr schema, const ::io_priority_class& iop, reshape_mode mode) override;

};

}
<commit_msg>compaction: make size_tiered_compaction_strategy static<commit_after>/*
 * Copyright (C) 2017-present ScyllaDB
 */

/*
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#pragma once

#include "compaction_strategy_impl.hh"
#include "compaction.hh"
#include "sstables/sstables.hh"
#include <boost/algorithm/cxx11/any_of.hpp>

namespace sstables {

class size_tiered_compaction_strategy_options {
    static constexpr uint64_t DEFAULT_MIN_SSTABLE_SIZE = 50L * 1024L * 1024L;
    static constexpr double DEFAULT_BUCKET_LOW = 0.5;
    static constexpr double DEFAULT_BUCKET_HIGH = 1.5;
    static constexpr double DEFAULT_COLD_READS_TO_OMIT = 0.05;
    const sstring MIN_SSTABLE_SIZE_KEY = "min_sstable_size";
    const sstring BUCKET_LOW_KEY = "bucket_low";
    const sstring BUCKET_HIGH_KEY = "bucket_high";
    const sstring COLD_READS_TO_OMIT_KEY = "cold_reads_to_omit";

    uint64_t min_sstable_size = DEFAULT_MIN_SSTABLE_SIZE;
    double bucket_low = DEFAULT_BUCKET_LOW;
    double bucket_high = DEFAULT_BUCKET_HIGH;
    double cold_reads_to_omit =  DEFAULT_COLD_READS_TO_OMIT;
public:
    size_tiered_compaction_strategy_options(const std::map<sstring, sstring>& options);

    size_tiered_compaction_strategy_options();

    // FIXME: convert java code below.
#if 0
    public static Map<String, String> validateOptions(Map<String, String> options, Map<String, String> uncheckedOptions) throws ConfigurationException
    {
        String optionValue = options.get(MIN_SSTABLE_SIZE_KEY);
        try
        {
            long minSSTableSize = optionValue == null ? DEFAULT_MIN_SSTABLE_SIZE : Long.parseLong(optionValue);
            if (minSSTableSize < 0)
            {
                throw new ConfigurationException(String.format("%s must be non negative: %d", MIN_SSTABLE_SIZE_KEY, minSSTableSize));
            }
        }
        catch (NumberFormatException e)
        {
            throw new ConfigurationException(String.format("%s is not a parsable int (base10) for %s", optionValue, MIN_SSTABLE_SIZE_KEY), e);
        }

        double bucketLow = parseDouble(options, BUCKET_LOW_KEY, DEFAULT_BUCKET_LOW);
        double bucketHigh = parseDouble(options, BUCKET_HIGH_KEY, DEFAULT_BUCKET_HIGH);
        if (bucketHigh <= bucketLow)
        {
            throw new ConfigurationException(String.format("%s value (%s) is less than or equal to the %s value (%s)",
                                                           BUCKET_HIGH_KEY, bucketHigh, BUCKET_LOW_KEY, bucketLow));
        }

        double maxColdReadsRatio = parseDouble(options, COLD_READS_TO_OMIT_KEY, DEFAULT_COLD_READS_TO_OMIT);
        if (maxColdReadsRatio < 0.0 || maxColdReadsRatio > 1.0)
        {
            throw new ConfigurationException(String.format("%s value (%s) should be between between 0.0 and 1.0",
                                                           COLD_READS_TO_OMIT_KEY, optionValue));
        }

        uncheckedOptions.remove(MIN_SSTABLE_SIZE_KEY);
        uncheckedOptions.remove(BUCKET_LOW_KEY);
        uncheckedOptions.remove(BUCKET_HIGH_KEY);
        uncheckedOptions.remove(COLD_READS_TO_OMIT_KEY);

        return uncheckedOptions;
    }
#endif
    friend class size_tiered_compaction_strategy;
};

class size_tiered_compaction_strategy : public compaction_strategy_impl {
    size_tiered_compaction_strategy_options _options;
    compaction_backlog_tracker _backlog_tracker;

    // Return a list of pair of shared_sstable and its respective size.
    static std::vector<std::pair<sstables::shared_sstable, uint64_t>> create_sstable_and_length_pairs(const std::vector<sstables::shared_sstable>& sstables);

    // Group files of similar size into buckets.
    static std::vector<std::vector<sstables::shared_sstable>> get_buckets(const std::vector<sstables::shared_sstable>& sstables, size_tiered_compaction_strategy_options options);

    std::vector<std::vector<sstables::shared_sstable>> get_buckets(const std::vector<sstables::shared_sstable>& sstables) const;

    // Maybe return a bucket of sstables to compact
    std::vector<sstables::shared_sstable>
    most_interesting_bucket(std::vector<std::vector<sstables::shared_sstable>> buckets, unsigned min_threshold, unsigned max_threshold);

    // Return the average size of a given list of sstables.
    uint64_t avg_size(std::vector<sstables::shared_sstable> const& sstables) const {
        assert(sstables.size() > 0); // this should never fail
        uint64_t n = 0;

        for (auto const& sstable : sstables) {
            n += sstable->data_size();
        }

        return n / sstables.size();
    }

    static bool is_bucket_interesting(const std::vector<sstables::shared_sstable>& bucket, int min_threshold) {
        return bucket.size() >= size_t(min_threshold);
    }

    bool is_any_bucket_interesting(const std::vector<std::vector<sstables::shared_sstable>>& buckets, int min_threshold) const {
        return boost::algorithm::any_of(buckets, [&] (const auto& bucket) {
            return this->is_bucket_interesting(bucket, min_threshold);
        });
    }
public:
    size_tiered_compaction_strategy() = default;

    size_tiered_compaction_strategy(const std::map<sstring, sstring>& options);
    explicit size_tiered_compaction_strategy(const size_tiered_compaction_strategy_options& options);

    virtual compaction_descriptor get_sstables_for_compaction(table_state& table_s, strategy_control& control, std::vector<sstables::shared_sstable> candidates) override;

    static int64_t estimated_pending_compactions(const std::vector<sstables::shared_sstable>& sstables,
        int min_threshold, int max_threshold, size_tiered_compaction_strategy_options options);
    virtual int64_t estimated_pending_compactions(table_state& table_s) const override;

    virtual compaction_strategy_type type() const override {
        return compaction_strategy_type::size_tiered;
    }

    // Return the most interesting bucket for a set of sstables
    static std::vector<sstables::shared_sstable>
    most_interesting_bucket(const std::vector<sstables::shared_sstable>& candidates, int min_threshold, int max_threshold,
        size_tiered_compaction_strategy_options options = {});

    virtual compaction_backlog_tracker& get_backlog_tracker() override {
        return _backlog_tracker;
    }

    virtual compaction_descriptor get_reshaping_job(std::vector<shared_sstable> input, schema_ptr schema, const ::io_priority_class& iop, reshape_mode mode) override;

};

}
<|endoftext|>


<commit_before>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) Andrey Mnatsakanov
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "gl.hpp"
#include <pangolin/gl/gl.h>
#include <pybind11/numpy.h>

namespace py_pangolin {

  bool is_packed(const pybind11::buffer_info & info) {
    int next_expected_stride = info.itemsize;
    for (int i = info.ndim-1; i >= 0; --i) {
      if (!(info.strides[i] == next_expected_stride)) {
        return false;
      }
      next_expected_stride *= info.shape[i];
    }
    return true;
  }

  void bind_gl(pybind11::module &m) {

    pybind11::class_<pangolin::GlTexture>(m, "GlTexture")
      .def(pybind11::init<>())
      .def(pybind11::init<GLint, GLint, GLint, bool, int, GLenum, GLenum>(), pybind11::arg("width"), pybind11::arg("height"), pybind11::arg("internal_format") = GL_RGBA8, pybind11::arg("sampling_linear") = true, pybind11::arg("border") = 0, pybind11::arg("glformat") = GL_RGBA, pybind11::arg("gltype") = GL_UNSIGNED_BYTE)
      .def("Reinitialise", &pangolin::GlTexture::Reinitialise)
      .def("Upload", [](pangolin::GlTexture & texture, pybind11::buffer b, GLenum data_format, GLenum type){
        pybind11::buffer_info info = b.request();
        texture.Upload(info.ptr, data_format, type);
      })
      .def("Download", [](pangolin::GlTexture & texture, pybind11::buffer b, GLenum data_layout, GLenum data_type) {
        pybind11::buffer_info info = b.request();
        if (!is_packed(info)) {
          throw std::runtime_error("cannot Download into non-packed buffer");
        }
        texture.Download(info.ptr, data_layout, data_type);
      })
      .def("Save", &pangolin::GlTexture::Save, pybind11::arg("filename"), pybind11::arg("top_line_first")=true)
      .def("RenderToViewport", (void (pangolin::GlTexture::*)() const)&pangolin::GlTexture::RenderToViewport)
      .def("RenderToViewportFlipY", &pangolin::GlTexture::RenderToViewportFlipY)
      .def("SetNearestNeighbour", &pangolin::GlTexture::SetNearestNeighbour);

    pybind11::class_<pangolin::GlRenderBuffer>(m, "GlRenderBuffer")
      .def(pybind11::init<GLint, GLint, GLint>(), pybind11::arg("width")=0, pybind11::arg("height")=0, pybind11::arg("internal_format") = GL_DEPTH_COMPONENT24)
      .def("Reinitialise", &pangolin::GlRenderBuffer::Reinitialise);

    pybind11::class_<pangolin::GlFramebuffer>(m, "GlFramebuffer")
      .def(pybind11::init<>())
      .def(pybind11::init<pangolin::GlTexture &, pangolin::GlRenderBuffer &>())
      .def("Reinitialise", &pangolin::GlFramebuffer::Reinitialise)
      .def("AttachColour", &pangolin::GlFramebuffer::AttachColour)
      .def("AttachDepth", &pangolin::GlFramebuffer::AttachDepth)
      .def("Bind", &pangolin::GlFramebuffer::Bind)
      .def("Unbind", &pangolin::GlFramebuffer::Unbind);

    pybind11::enum_<pangolin::GlBufferType>(m, "GlBufferType")
      .value("GlUndefined", pangolin::GlBufferType::GlUndefined)
      .value("GlArrayBuffer", pangolin::GlBufferType::GlArrayBuffer)
      .value("GlElementArrayBuffer", pangolin::GlBufferType::GlElementArrayBuffer)
#ifndef HAVE_GLES
      .value("GlPixelPackBuffer", pangolin::GlBufferType::GlPixelPackBuffer)
      .value("GlPixelUnpackBuffer", pangolin::GlBufferType::GlPixelUnpackBuffer)
      .value("GlShaderStorageBuffer", pangolin::GlBufferType::GlShaderStorageBuffer)
#endif
      .export_values();

    pybind11::class_<pangolin::GlBufferData>(m, "GlBufferData")
      .def(pybind11::init<>())
      .def("Reinitialise", [](pangolin::GlBufferData & gl_buffer, pangolin::GlBufferType buffer_type, GLuint size_bytes, GLenum gl_use) {
        gl_buffer.Reinitialise(buffer_type, size_bytes, gl_use);
      })
      .def("Bind", &pangolin::GlBufferData::Bind)
      .def("Unbind", &pangolin::GlBufferData::Unbind)
      .def("Upload", [](pangolin::GlBufferData & gl_buffer, pybind11::buffer b, GLsizeiptr size_bytes, GLintptr offset) {
        pybind11::buffer_info info = b.request();
        gl_buffer.Upload(info.ptr, size_bytes, offset);
      }, pybind11::arg("data"), pybind11::arg("size_bytes"), pybind11::arg("offset")=0)
      .def_readwrite("size_bytes", &pangolin::GlBufferData::size_bytes);

    pybind11::class_<pangolin::GlBuffer, pangolin::GlBufferData>(m, "GlBuffer")
      .def(pybind11::init<>())
      .def(pybind11::init<pangolin::GlBufferType, GLuint, GLenum, GLuint, GLenum>(), pybind11::arg("buffer_type"), pybind11::arg("num_elements"), pybind11::arg("datatype"), pybind11::arg("count_per_element"), pybind11::arg("gluse")=GL_DYNAMIC_DRAW)
      .def("Resize", &pangolin::GlBuffer::Resize, pybind11::arg("num_elements"))
      .def_readwrite("num_elements", &pangolin::GlBuffer::num_elements)
      .def_readwrite("count_per_element", &pangolin::GlBuffer::count_per_element);

  }

} // namespace py_pangolin
<commit_msg>Expose additional GlTexture functionality to pypangolin<commit_after>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) Andrey Mnatsakanov
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "gl.hpp"
#include <pangolin/gl/gl.h>
#include <pybind11/numpy.h>

namespace py_pangolin {

  bool is_packed(const pybind11::buffer_info & info) {
    int next_expected_stride = info.itemsize;
    for (int i = info.ndim-1; i >= 0; --i) {
      if (!(info.strides[i] == next_expected_stride)) {
        return false;
      }
      next_expected_stride *= info.shape[i];
    }
    return true;
  }

  void bind_gl(pybind11::module &m) {

    pybind11::class_<pangolin::GlTexture>(m, "GlTexture")
      .def(pybind11::init<>())
      .def(pybind11::init<GLint, GLint, GLint, bool, int, GLenum, GLenum>(), pybind11::arg("width"), pybind11::arg("height"), pybind11::arg("internal_format") = GL_RGBA8, pybind11::arg("sampling_linear") = true, pybind11::arg("border") = 0, pybind11::arg("glformat") = GL_RGBA, pybind11::arg("gltype") = GL_UNSIGNED_BYTE)
      .def("Reinitialise", &pangolin::GlTexture::Reinitialise)
      .def("Id", [](pangolin::GlTexture & texture){ return texture.tid; })
      .def("Bind", &pangolin::GlTexture::Bind)
      .def("Unbind", &pangolin::GlTexture::Unbind)
      .def("Upload", [](pangolin::GlTexture & texture, pybind11::buffer b, GLenum data_format, GLenum type){
        pybind11::buffer_info info = b.request();
        texture.Upload(info.ptr, data_format, type);
      })
      .def("Download", [](pangolin::GlTexture & texture, pybind11::buffer b, GLenum data_layout, GLenum data_type) {
        pybind11::buffer_info info = b.request();
        if (!is_packed(info)) {
          throw std::runtime_error("cannot Download into non-packed buffer");
        }
        texture.Download(info.ptr, data_layout, data_type);
      })
      .def("Save", &pangolin::GlTexture::Save, pybind11::arg("filename"), pybind11::arg("top_line_first")=true)
      .def("RenderToViewport", (void (pangolin::GlTexture::*)() const)&pangolin::GlTexture::RenderToViewport)
      .def("RenderToViewportFlipY", &pangolin::GlTexture::RenderToViewportFlipY)
      .def("SetNearestNeighbour", &pangolin::GlTexture::SetNearestNeighbour);

    pybind11::class_<pangolin::GlRenderBuffer>(m, "GlRenderBuffer")
      .def(pybind11::init<GLint, GLint, GLint>(), pybind11::arg("width")=0, pybind11::arg("height")=0, pybind11::arg("internal_format") = GL_DEPTH_COMPONENT24)
      .def("Reinitialise", &pangolin::GlRenderBuffer::Reinitialise);

    pybind11::class_<pangolin::GlFramebuffer>(m, "GlFramebuffer")
      .def(pybind11::init<>())
      .def(pybind11::init<pangolin::GlTexture &, pangolin::GlRenderBuffer &>())
      .def("Reinitialise", &pangolin::GlFramebuffer::Reinitialise)
      .def("AttachColour", &pangolin::GlFramebuffer::AttachColour)
      .def("AttachDepth", &pangolin::GlFramebuffer::AttachDepth)
      .def("Bind", &pangolin::GlFramebuffer::Bind)
      .def("Unbind", &pangolin::GlFramebuffer::Unbind);

    pybind11::enum_<pangolin::GlBufferType>(m, "GlBufferType")
      .value("GlUndefined", pangolin::GlBufferType::GlUndefined)
      .value("GlArrayBuffer", pangolin::GlBufferType::GlArrayBuffer)
      .value("GlElementArrayBuffer", pangolin::GlBufferType::GlElementArrayBuffer)
#ifndef HAVE_GLES
      .value("GlPixelPackBuffer", pangolin::GlBufferType::GlPixelPackBuffer)
      .value("GlPixelUnpackBuffer", pangolin::GlBufferType::GlPixelUnpackBuffer)
      .value("GlShaderStorageBuffer", pangolin::GlBufferType::GlShaderStorageBuffer)
#endif
      .export_values();

    pybind11::class_<pangolin::GlBufferData>(m, "GlBufferData")
      .def(pybind11::init<>())
      .def("Reinitialise", [](pangolin::GlBufferData & gl_buffer, pangolin::GlBufferType buffer_type, GLuint size_bytes, GLenum gl_use) {
        gl_buffer.Reinitialise(buffer_type, size_bytes, gl_use);
      })
      .def("Bind", &pangolin::GlBufferData::Bind)
      .def("Unbind", &pangolin::GlBufferData::Unbind)
      .def("Upload", [](pangolin::GlBufferData & gl_buffer, pybind11::buffer b, GLsizeiptr size_bytes, GLintptr offset) {
        pybind11::buffer_info info = b.request();
        gl_buffer.Upload(info.ptr, size_bytes, offset);
      }, pybind11::arg("data"), pybind11::arg("size_bytes"), pybind11::arg("offset")=0)
      .def_readwrite("size_bytes", &pangolin::GlBufferData::size_bytes);

    pybind11::class_<pangolin::GlBuffer, pangolin::GlBufferData>(m, "GlBuffer")
      .def(pybind11::init<>())
      .def(pybind11::init<pangolin::GlBufferType, GLuint, GLenum, GLuint, GLenum>(), pybind11::arg("buffer_type"), pybind11::arg("num_elements"), pybind11::arg("datatype"), pybind11::arg("count_per_element"), pybind11::arg("gluse")=GL_DYNAMIC_DRAW)
      .def("Resize", &pangolin::GlBuffer::Resize, pybind11::arg("num_elements"))
      .def_readwrite("num_elements", &pangolin::GlBuffer::num_elements)
      .def_readwrite("count_per_element", &pangolin::GlBuffer::count_per_element);

  }

} // namespace py_pangolin
<|endoftext|>