<commit_before>// call from command line like, for instance:
// root -l 'vincemark.cpp()'

#include <chrono>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <unistd.h>  // usleep
#include <sys/types.h>  // for kill
#include <signal.h>     // for kill

using namespace RooFit;

std::string cut_between(std::string input, std::string before, std::string after) {
  auto before_pos = input.find(before);
  auto after_pos = input.find(after);
  auto cut_pos = before_pos + before.length();
  auto cut_len = after_pos - cut_pos;
  std::string output = input.substr(cut_pos, cut_len);
  return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// timing_flag is used to activate only selected timing statements [1-7]
// num_cpu: -1 is special option -> compare overhead communication protocol (wrt 1 cpu)
// parallel_interleave: 0 = blocks of equal size, 1 = interleave
////////////////////////////////////////////////////////////////////////////////////////////////////

void vincemark(std::string workspace_filepath,
               int num_cpu=1,
               int optConst=0,
               int parallel_interleave=0,
               bool cpu_affinity=true,
               int seed=1,
               int timing_flag=1,
               bool time_num_ints=false,
               bool fork_timer = false,
               int fork_timer_sleep_us = 100000,
               int print_level=0,
               bool debug=false
               ) {
  if (debug) {
    RooMsgService::instance().addStream(DEBUG);
    // extra possible options: Topic(Generation) Topic(RooFit::Eval), ClassName("RooAbsTestStatistic")
  }

  // int N_parameters(8);  // must be even, means and sigmas have diff ranges

  if (timing_flag > 0) {
    RooJsonListFile outfile;

    outfile.open("timing_meta.json");
    std::string names[13] = {"workspace_filepath",
                             "N_chans", "N_bins", "N_nuisance_parameters",
                             "N_events", "num_cpu", "parallel_interleave",
                             "seed", "pid", "time_num_ints",
                             "optConst", "print_level", "timing_flag"};
    outfile.set_member_names(names, names + 13);

    auto workspace_fn = workspace_filepath.substr(workspace_filepath.rfind("/"));

    std::string N_channels = cut_between(workspace_fn, "workspace", "channels");
    std::string N_events = cut_between(workspace_fn, "channels", "events");
    std::string N_bins = cut_between(workspace_fn, "events", "bins");
    std::string N_nuisance_parameters = cut_between(workspace_fn, "bins", "nps");

    outfile << workspace_filepath << N_channels << N_bins << N_nuisance_parameters
            << N_events << num_cpu << parallel_interleave
            << seed << getpid() << time_num_ints
            << optConst << print_level << timing_flag;
  }

  RooTrace::timing_flag = timing_flag;
  if (time_num_ints) {
    RooTrace::set_time_numInts(kTRUE);
  }

  // plotting configuration
  int obs_plot_x(3);
  int obs_plot_y(2);
  int obs_plot_x_px(1200);
  int obs_plot_y_px(800);

  // other stuff
  int printlevel(print_level);
  int optimizeConst(optConst);
  // int N_timing_loops(3); // not used

  gRandom->SetSeed(seed);

  // Load the workspace data and pdf
  TFile *_file0 = TFile::Open(workspace_filepath.c_str());

  RooWorkspace* w = static_cast<RooWorkspace*>(gDirectory->Get("BinnedWorkspace"));
  RooStats::ModelConfig* mc = static_cast<RooStats::ModelConfig*>(w->genobj("ModelConfig"));

  RooAbsPdf* pdf = w->pdf(mc->GetPdf()->GetName()) ;
  RooAbsData * data = w->data("obsData");

  // --- Perform extended ML fit of composite PDF to data ---

  RooJsonListFile outfile;
  RooWallTimer timer;

  if (timing_flag == 1) {
    outfile.open("timing_full_minimize.json");
    outfile.add_member_name("walltime_s")
           .add_member_name("segment")
           .add_member_name("pid");
  }

  Bool_t cpuAffinity;
  if (cpu_affinity) {
    cpuAffinity = kTRUE;
  } else {
    cpuAffinity = kFALSE;
  }

  // for (int it = 0; it < N_timing_loops; ++it)
  {
    RooAbsReal* nll = pdf->createNLL(*data, NumCPU(num_cpu, parallel_interleave),
                                     CPUAffinity(cpuAffinity));//, "Extended");
    RooMinimizer m(*nll);
    // m.setVerbose(1);
    m.setStrategy(0);
    m.setProfile(1);
    m.setPrintLevel(printlevel);
    m.optimizeConst(optimizeConst);

    int pid = -1;

    if (fork_timer) {
      pid = fork();
    }
    if (pid == 0) {
      /* child */
      timer.start();
      while (true) {
        timer.stop();
        std::cout << "TIME: " << timer.timing_s() << "s" << std::endl;
        usleep(fork_timer_sleep_us);
      }
    }
    else {
      /* parent */

      double time_migrad, time_hesse, time_minos;

      if (timing_flag == 1) {
        timer.start();
      }
      // m.hesse();

      m.migrad();

      if (timing_flag == 1) {
        timer.stop();
        std::cout << "TIME migrad: " << timer.timing_s() << "s" << std::endl;
        outfile << timer.timing_s() << "migrad" << getpid();
        time_migrad = timer.timing_s();

        timer.start();
      }

      m.hesse();

      if (timing_flag == 1) {
        timer.stop();
        std::cout << "TIME hesse: " << timer.timing_s() << "s" << std::endl;
        outfile << timer.timing_s() << "hesse" << getpid();
        time_hesse = timer.timing_s();

        timer.start();
      }

      m.minos(*mc->GetParametersOfInterest());

      if (timing_flag == 1) {
        timer.stop();
        std::cout << "TIME minos: " << timer.timing_s() << "s" << std::endl;
        outfile << timer.timing_s() << "minos" << getpid();
        time_minos = timer.timing_s();

        outfile << (time_migrad + time_hesse + time_minos) << "migrad+hesse+minos" << getpid();
      }

      if (pid > 0) {
        // a child exists
        kill(pid, SIGKILL);
      }
    }
  }
}
<commit_msg>Fix vincemark; need to preload libRooFit for clang<commit_after>// call from command line like, for instance:
// root -l 'vincemark.cpp()'

R__LOAD_LIBRARY(libRooFit)

#include <chrono>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <unistd.h>  // usleep
#include <sys/types.h>  // for kill
#include <signal.h>     // for kill

using namespace RooFit;

std::string cut_between(std::string input, std::string before, std::string after) {
  auto before_pos = input.find(before);
  auto after_pos = input.find(after);
  auto cut_pos = before_pos + before.length();
  auto cut_len = after_pos - cut_pos;
  std::string output = input.substr(cut_pos, cut_len);
  return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// timing_flag is used to activate only selected timing statements [1-7]
// num_cpu: -1 is special option -> compare overhead communication protocol (wrt 1 cpu)
// parallel_interleave: 0 = blocks of equal size, 1 = interleave
////////////////////////////////////////////////////////////////////////////////////////////////////

void vincemark(std::string workspace_filepath,
               int num_cpu=1,
               int optConst=0,
               int parallel_interleave=0,
               bool cpu_affinity=true,
               int seed=1,
               int timing_flag=1,
               bool time_num_ints=false,
               bool fork_timer = false,
               int fork_timer_sleep_us = 100000,
               int print_level=0,
               bool debug=false
               ) {
  if (debug) {
    RooMsgService::instance().addStream(DEBUG);
    // extra possible options: Topic(Generation) Topic(RooFit::Eval), ClassName("RooAbsTestStatistic")
  }

  // int N_parameters(8);  // must be even, means and sigmas have diff ranges

  if (timing_flag > 0) {
    RooJsonListFile outfile;

    outfile.open("timing_meta.json");
    std::string names[13] = {"workspace_filepath",
                             "N_chans", "N_bins", "N_nuisance_parameters",
                             "N_events", "num_cpu", "parallel_interleave",
                             "seed", "pid", "time_num_ints",
                             "optConst", "print_level", "timing_flag"};
    outfile.set_member_names(names, names + 13);

    auto workspace_fn = workspace_filepath.substr(workspace_filepath.rfind("/"));

    std::string N_channels = cut_between(workspace_fn, "workspace", "channels");
    std::string N_events = cut_between(workspace_fn, "channels", "events");
    std::string N_bins = cut_between(workspace_fn, "events", "bins");
    std::string N_nuisance_parameters = cut_between(workspace_fn, "bins", "nps");

    outfile << workspace_filepath << N_channels << N_bins << N_nuisance_parameters
            << N_events << num_cpu << parallel_interleave
            << seed << getpid() << time_num_ints
            << optConst << print_level << timing_flag;
  }

  RooTrace::timing_flag = timing_flag;
  if (time_num_ints) {
    RooTrace::set_time_numInts(kTRUE);
  }

  // plotting configuration
  int obs_plot_x(3);
  int obs_plot_y(2);
  int obs_plot_x_px(1200);
  int obs_plot_y_px(800);

  // other stuff
  int printlevel(print_level);
  int optimizeConst(optConst);
  // int N_timing_loops(3); // not used

  gRandom->SetSeed(seed);

  // Load the workspace data and pdf
  TFile *_file0 = TFile::Open(workspace_filepath.c_str());

  RooWorkspace* w = static_cast<RooWorkspace*>(gDirectory->Get("BinnedWorkspace"));
  RooStats::ModelConfig* mc = static_cast<RooStats::ModelConfig*>(w->genobj("ModelConfig"));

  RooAbsPdf* pdf = w->pdf(mc->GetPdf()->GetName()) ;
  RooAbsData * data = w->data("obsData");

  // --- Perform extended ML fit of composite PDF to data ---

  RooJsonListFile outfile;
  RooWallTimer timer;

  if (timing_flag == 1) {
    outfile.open("timing_full_minimize.json");
    outfile.add_member_name("walltime_s")
           .add_member_name("segment")
           .add_member_name("pid");
  }

  Bool_t cpuAffinity;
  if (cpu_affinity) {
    cpuAffinity = kTRUE;
  } else {
    cpuAffinity = kFALSE;
  }

  // for (int it = 0; it < N_timing_loops; ++it)
  {
    RooAbsReal* nll = pdf->createNLL(*data, NumCPU(num_cpu, parallel_interleave),
                                     CPUAffinity(cpuAffinity));//, "Extended");
    RooMinimizer m(*nll);
    // m.setVerbose(1);
    m.setStrategy(0);
    m.setProfile(1);
    m.setPrintLevel(printlevel);
    m.optimizeConst(optimizeConst);

    int pid = -1;

    if (fork_timer) {
      pid = fork();
    }
    if (pid == 0) {
      /* child */
      timer.start();
      while (true) {
        timer.stop();
        std::cout << "TIME: " << timer.timing_s() << "s" << std::endl;
        usleep(fork_timer_sleep_us);
      }
    }
    else {
      /* parent */

      double time_migrad, time_hesse, time_minos;

      if (timing_flag == 1) {
        timer.start();
      }
      // m.hesse();

      m.migrad();

      if (timing_flag == 1) {
        timer.stop();
        std::cout << "TIME migrad: " << timer.timing_s() << "s" << std::endl;
        outfile << timer.timing_s() << "migrad" << getpid();
        time_migrad = timer.timing_s();

        timer.start();
      }

      m.hesse();

      if (timing_flag == 1) {
        timer.stop();
        std::cout << "TIME hesse: " << timer.timing_s() << "s" << std::endl;
        outfile << timer.timing_s() << "hesse" << getpid();
        time_hesse = timer.timing_s();

        timer.start();
      }

      m.minos(*mc->GetParametersOfInterest());

      if (timing_flag == 1) {
        timer.stop();
        std::cout << "TIME minos: " << timer.timing_s() << "s" << std::endl;
        outfile << timer.timing_s() << "minos" << getpid();
        time_minos = timer.timing_s();

        outfile << (time_migrad + time_hesse + time_minos) << "migrad+hesse+minos" << getpid();
      }

      if (pid > 0) {
        // a child exists
        kill(pid, SIGKILL);
      }
    }
  }
}
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2018 Baldur Karlsson
 *
 * 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 "vk_core.h"
#include "vk_replay.h"

static int dllLocator = 0;

void VulkanReplay::OutputWindow::SetWindowHandle(WindowingData window)
{
  RDCASSERT(window.system == WindowingSystem::Win32, window.system);
  wnd = window.win32.window;
}

void VulkanReplay::OutputWindow::CreateSurface(VkInstance inst)
{
  VkWin32SurfaceCreateInfoKHR createInfo;

  createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
  createInfo.pNext = NULL;
  createInfo.flags = 0;
  createInfo.hwnd = wnd;

  GetModuleHandleExA(
      GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
      (const char *)&dllLocator, (HMODULE *)&createInfo.hinstance);

  VkResult vkr = ObjDisp(inst)->CreateWin32SurfaceKHR(Unwrap(inst), &createInfo, NULL, &surface);
  RDCASSERTEQUAL(vkr, VK_SUCCESS);
}

void VulkanReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
{
  if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
    return;

  OutputWindow &outw = m_OutputWindows[id];

  RECT rect = {0};
  GetClientRect(outw.wnd, &rect);
  w = rect.right - rect.left;
  h = rect.bottom - rect.top;
}

bool VulkanReplay::IsOutputWindowVisible(uint64_t id)
{
  if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
    return false;

  return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE);
}

void WrappedVulkan::AddRequiredExtensions(bool instance, vector<string> &extensionList,
                                          const std::set<string> &supportedExtensions)
{
  bool device = !instance;

  if(instance)
  {
    // for windows we require both extensions as there's no alternative
    if(supportedExtensions.find(VK_KHR_SURFACE_EXTENSION_NAME) == supportedExtensions.end())
    {
      RDCERR("Unsupported required instance extension '%s'", VK_KHR_SURFACE_EXTENSION_NAME);
    }
    else
    {
      // don't add duplicates
      if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_SURFACE_EXTENSION_NAME) ==
         extensionList.end())
        extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
    }

    if(supportedExtensions.find(VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == supportedExtensions.end())
    {
      RDCERR("Unsupported required instance extension '%s'", VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
    }
    else
    {
      if(std::find(extensionList.begin(), extensionList.end(),
                   VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == extensionList.end())
        extensionList.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
    }
  }
  else if(device)
  {
    if(supportedExtensions.find(VK_KHR_SWAPCHAIN_EXTENSION_NAME) == supportedExtensions.end())
    {
      RDCERR("Unsupported required device extension '%s'", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    }
    else
    {
      // don't add duplicates
      if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_SWAPCHAIN_EXTENSION_NAME) ==
         extensionList.end())
        extensionList.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    }
  }
}

#if !defined(VK_USE_PLATFORM_WIN32_KHR)
#error "Win32 KHR platform not defined"
#endif

VkResult WrappedVulkan::vkCreateWin32SurfaceKHR(VkInstance instance,
                                                const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
                                                const VkAllocationCallbacks *pAllocator,
                                                VkSurfaceKHR *pSurface)
{
  // should not come in here at all on replay
  RDCASSERT(IsCaptureMode(m_State));

  VkResult ret =
      ObjDisp(instance)->CreateWin32SurfaceKHR(Unwrap(instance), pCreateInfo, pAllocator, pSurface);

  if(ret == VK_SUCCESS)
  {
    GetResourceManager()->WrapResource(Unwrap(instance), *pSurface);

    WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);

    // since there's no point in allocating a full resource record and storing the window
    // handle under there somewhere, we just cast. We won't use the resource record for anything
    wrapped->record = (VkResourceRecord *)pCreateInfo->hwnd;

    Keyboard::AddInputWindow((void *)pCreateInfo->hwnd);
  }

  return ret;
}

VkBool32 WrappedVulkan::vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
                                                                       uint32_t queueFamilyIndex)
{
  return ObjDisp(physicalDevice)
      ->GetPhysicalDeviceWin32PresentationSupportKHR(Unwrap(physicalDevice), queueFamilyIndex);
}

void *LoadVulkanLibrary()
{
  return Process::LoadModule("vulkan-1.dll");
}

std::wstring GetJSONPath(bool wow6432)
{
  wchar_t curFile[1024];
  GetModuleFileNameW(NULL, curFile, 1024);

  wchar_t *lastSlash = wcsrchr(curFile, '\\');
  if(lastSlash)
    *(lastSlash + 1) = 0;

  if(wow6432)
    wcscat_s(curFile, L"x86\\");

  wcscat_s(curFile, L"renderdoc.json");

  return curFile;
}

static HKEY GetImplicitLayersKey(bool writeable, bool wow6432)
{
  std::string basepath = "SOFTWARE\\";

  if(wow6432)
    basepath += "Wow6432Node\\";

  basepath += "Khronos\\Vulkan\\ImplicitLayers";

  HKEY key = NULL;
  LSTATUS ret = ERROR_SUCCESS;

  if(writeable)
    ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, basepath.c_str(), 0, NULL, 0, KEY_READ | KEY_WRITE,
                          NULL, &key, NULL);
  else
    ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, basepath.c_str(), 0, KEY_READ, &key);

  if(ret != ERROR_SUCCESS)
  {
    if(key)
      RegCloseKey(key);

    // find to fail to open for read, the key may not exist
    if(writeable)
      RDCERR("Couldn't open %s for write", basepath.c_str());

    return NULL;
  }

  return key;
}

bool ProcessImplicitLayersKey(HKEY key, const std::wstring &path,
                              std::vector<std::string> *otherJSONs, bool deleteOthers)
{
  bool thisRegistered = false;

  wchar_t name[1025] = {};
  DWORD nameSize = 1024;
  DWORD idx = 0;

  LONG ret = RegEnumValueW(key, idx++, name, &nameSize, NULL, NULL, NULL, NULL);

  std::wstring myJSON = path;
  for(size_t i = 0; i < myJSON.size(); i++)
    myJSON[i] = towlower(myJSON[i]);

  while(ret == ERROR_SUCCESS)
  {
    // convert the name here so we preserve casing
    std::string utf8name = StringFormat::Wide2UTF8(name);

    for(DWORD i = 0; i <= nameSize && name[i]; i++)
      name[i] = towlower(name[i]);

    if(wcscmp(name, myJSON.c_str()) == 0)
    {
      thisRegistered = true;
    }
    else if(wcsstr(name, L"renderdoc.json") != NULL)
    {
      if(otherJSONs)
        otherJSONs->push_back(utf8name);

      if(deleteOthers)
        RegDeleteValueW(key, name);
    }

    nameSize = 1024;
    ret = RegEnumValueW(key, idx++, name, &nameSize, NULL, NULL, NULL, NULL);
  }

  return thisRegistered;
}

bool VulkanReplay::CheckVulkanLayer(VulkanLayerFlags &flags, std::vector<std::string> &myJSONs,
                                    std::vector<std::string> &otherJSONs)
{
  std::wstring normalPath = GetJSONPath(false);
  myJSONs.push_back(StringFormat::Wide2UTF8(normalPath));

#if ENABLED(RDOC_X64)
  std::wstring wow6432Path = GetJSONPath(true);
  myJSONs.push_back(StringFormat::Wide2UTF8(wow6432Path));
#endif

  HKEY key = GetImplicitLayersKey(false, false);

  // if we couldn't even get the ImplicitLayers reg key the system doesn't have the
  // vulkan runtime, so we return as if we are not registered (as that's the case).
  // People not using vulkan can either ignore the message, or click to set it up
  // and it will go away as we'll have rights to create it.
  if(!key)
  {
    flags = VulkanLayerFlags::NeedElevation | VulkanLayerFlags::RegisterAll;
    return true;
  }

  bool thisRegistered = ProcessImplicitLayersKey(key, normalPath, &otherJSONs, false);

  RegCloseKey(key);

#if ENABLED(RDOC_X64)
  {
    key = GetImplicitLayersKey(false, true);

    if(key)
    {
      // if we're on 64-bit, the layer isn't registered unless both keys are registered.
      thisRegistered &= ProcessImplicitLayersKey(key, wow6432Path, &otherJSONs, false);

      RegCloseKey(key);
    }
    else
    {
      flags = VulkanLayerFlags::NeedElevation | VulkanLayerFlags::RegisterAll;
      return true;
    }
  }
#endif

  flags = VulkanLayerFlags::NeedElevation | VulkanLayerFlags::RegisterAll;

  if(thisRegistered)
    flags |= VulkanLayerFlags::ThisInstallRegistered;

  if(!otherJSONs.empty())
    flags |= VulkanLayerFlags::OtherInstallsRegistered;

  // return true if any changes are needed
  return !otherJSONs.empty() || !thisRegistered;
}

void VulkanReplay::InstallVulkanLayer(bool systemLevel)
{
  HKEY key = GetImplicitLayersKey(true, false);

  const DWORD zero = 0;

  if(key)
  {
    std::wstring path = GetJSONPath(false);

    // this function will delete all non-matching renderdoc.json values, and return true if our own
    // is registered
    bool thisRegistered = ProcessImplicitLayersKey(key, path, NULL, true);

    if(!thisRegistered)
      RegSetValueExW(key, path.c_str(), 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero));

    RegCloseKey(key);
  }

// if we're a 64-bit process, update the 32-bit key
#if ENABLED(RDOC_X64)
  {
    key = GetImplicitLayersKey(true, true);

    if(key)
    {
      std::wstring path = GetJSONPath(true);

      // this function will delete all non-matching renderdoc.json values, and return true if our
      // own is registered
      bool thisRegistered = ProcessImplicitLayersKey(key, path, NULL, true);

      if(!thisRegistered)
        RegSetValueExW(key, path.c_str(), 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero));

      RegCloseKey(key);
    }
  }
#endif
}
<commit_msg>vulkan json on windows is located adjacent to renderdoc.dll, not exe<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2018 Baldur Karlsson
 *
 * 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 "strings/string_utils.h"
#include "vk_core.h"
#include "vk_replay.h"

static int dllLocator = 0;

void VulkanReplay::OutputWindow::SetWindowHandle(WindowingData window)
{
  RDCASSERT(window.system == WindowingSystem::Win32, window.system);
  wnd = window.win32.window;
}

void VulkanReplay::OutputWindow::CreateSurface(VkInstance inst)
{
  VkWin32SurfaceCreateInfoKHR createInfo;

  createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
  createInfo.pNext = NULL;
  createInfo.flags = 0;
  createInfo.hwnd = wnd;

  GetModuleHandleExA(
      GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
      (const char *)&dllLocator, (HMODULE *)&createInfo.hinstance);

  VkResult vkr = ObjDisp(inst)->CreateWin32SurfaceKHR(Unwrap(inst), &createInfo, NULL, &surface);
  RDCASSERTEQUAL(vkr, VK_SUCCESS);
}

void VulkanReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
{
  if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
    return;

  OutputWindow &outw = m_OutputWindows[id];

  RECT rect = {0};
  GetClientRect(outw.wnd, &rect);
  w = rect.right - rect.left;
  h = rect.bottom - rect.top;
}

bool VulkanReplay::IsOutputWindowVisible(uint64_t id)
{
  if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
    return false;

  return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE);
}

void WrappedVulkan::AddRequiredExtensions(bool instance, vector<string> &extensionList,
                                          const std::set<string> &supportedExtensions)
{
  bool device = !instance;

  if(instance)
  {
    // for windows we require both extensions as there's no alternative
    if(supportedExtensions.find(VK_KHR_SURFACE_EXTENSION_NAME) == supportedExtensions.end())
    {
      RDCERR("Unsupported required instance extension '%s'", VK_KHR_SURFACE_EXTENSION_NAME);
    }
    else
    {
      // don't add duplicates
      if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_SURFACE_EXTENSION_NAME) ==
         extensionList.end())
        extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
    }

    if(supportedExtensions.find(VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == supportedExtensions.end())
    {
      RDCERR("Unsupported required instance extension '%s'", VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
    }
    else
    {
      if(std::find(extensionList.begin(), extensionList.end(),
                   VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == extensionList.end())
        extensionList.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
    }
  }
  else if(device)
  {
    if(supportedExtensions.find(VK_KHR_SWAPCHAIN_EXTENSION_NAME) == supportedExtensions.end())
    {
      RDCERR("Unsupported required device extension '%s'", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    }
    else
    {
      // don't add duplicates
      if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_SWAPCHAIN_EXTENSION_NAME) ==
         extensionList.end())
        extensionList.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    }
  }
}

#if !defined(VK_USE_PLATFORM_WIN32_KHR)
#error "Win32 KHR platform not defined"
#endif

VkResult WrappedVulkan::vkCreateWin32SurfaceKHR(VkInstance instance,
                                                const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
                                                const VkAllocationCallbacks *pAllocator,
                                                VkSurfaceKHR *pSurface)
{
  // should not come in here at all on replay
  RDCASSERT(IsCaptureMode(m_State));

  VkResult ret =
      ObjDisp(instance)->CreateWin32SurfaceKHR(Unwrap(instance), pCreateInfo, pAllocator, pSurface);

  if(ret == VK_SUCCESS)
  {
    GetResourceManager()->WrapResource(Unwrap(instance), *pSurface);

    WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);

    // since there's no point in allocating a full resource record and storing the window
    // handle under there somewhere, we just cast. We won't use the resource record for anything
    wrapped->record = (VkResourceRecord *)pCreateInfo->hwnd;

    Keyboard::AddInputWindow((void *)pCreateInfo->hwnd);
  }

  return ret;
}

VkBool32 WrappedVulkan::vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
                                                                       uint32_t queueFamilyIndex)
{
  return ObjDisp(physicalDevice)
      ->GetPhysicalDeviceWin32PresentationSupportKHR(Unwrap(physicalDevice), queueFamilyIndex);
}

void *LoadVulkanLibrary()
{
  return Process::LoadModule("vulkan-1.dll");
}

std::wstring GetJSONPath(bool wow6432)
{
  std::string libPath;
  FileIO::GetLibraryFilename(libPath);
  std::string jsonPath = dirname(FileIO::GetFullPathname(libPath));

  if(wow6432)
    jsonPath += "\\x86";

  jsonPath += "\\renderdoc.json";

  return StringFormat::UTF82Wide(jsonPath);
}

static HKEY GetImplicitLayersKey(bool writeable, bool wow6432)
{
  std::string basepath = "SOFTWARE\\";

  if(wow6432)
    basepath += "Wow6432Node\\";

  basepath += "Khronos\\Vulkan\\ImplicitLayers";

  HKEY key = NULL;
  LSTATUS ret = ERROR_SUCCESS;

  if(writeable)
    ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, basepath.c_str(), 0, NULL, 0, KEY_READ | KEY_WRITE,
                          NULL, &key, NULL);
  else
    ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, basepath.c_str(), 0, KEY_READ, &key);

  if(ret != ERROR_SUCCESS)
  {
    if(key)
      RegCloseKey(key);

    // find to fail to open for read, the key may not exist
    if(writeable)
      RDCERR("Couldn't open %s for write", basepath.c_str());

    return NULL;
  }

  return key;
}

bool ProcessImplicitLayersKey(HKEY key, const std::wstring &path,
                              std::vector<std::string> *otherJSONs, bool deleteOthers)
{
  bool thisRegistered = false;

  wchar_t name[1025] = {};
  DWORD nameSize = 1024;
  DWORD idx = 0;

  LONG ret = RegEnumValueW(key, idx++, name, &nameSize, NULL, NULL, NULL, NULL);

  std::wstring myJSON = path;
  for(size_t i = 0; i < myJSON.size(); i++)
    myJSON[i] = towlower(myJSON[i]);

  while(ret == ERROR_SUCCESS)
  {
    // convert the name here so we preserve casing
    std::string utf8name = StringFormat::Wide2UTF8(name);

    for(DWORD i = 0; i <= nameSize && name[i]; i++)
      name[i] = towlower(name[i]);

    if(wcscmp(name, myJSON.c_str()) == 0)
    {
      thisRegistered = true;
    }
    else if(wcsstr(name, L"renderdoc.json") != NULL)
    {
      if(otherJSONs)
        otherJSONs->push_back(utf8name);

      if(deleteOthers)
        RegDeleteValueW(key, name);
    }

    nameSize = 1024;
    ret = RegEnumValueW(key, idx++, name, &nameSize, NULL, NULL, NULL, NULL);
  }

  return thisRegistered;
}

bool VulkanReplay::CheckVulkanLayer(VulkanLayerFlags &flags, std::vector<std::string> &myJSONs,
                                    std::vector<std::string> &otherJSONs)
{
  std::wstring normalPath = GetJSONPath(false);
  myJSONs.push_back(StringFormat::Wide2UTF8(normalPath));

#if ENABLED(RDOC_X64)
  std::wstring wow6432Path = GetJSONPath(true);
  myJSONs.push_back(StringFormat::Wide2UTF8(wow6432Path));
#endif

  HKEY key = GetImplicitLayersKey(false, false);

  // if we couldn't even get the ImplicitLayers reg key the system doesn't have the
  // vulkan runtime, so we return as if we are not registered (as that's the case).
  // People not using vulkan can either ignore the message, or click to set it up
  // and it will go away as we'll have rights to create it.
  if(!key)
  {
    flags = VulkanLayerFlags::NeedElevation | VulkanLayerFlags::RegisterAll;
    return true;
  }

  bool thisRegistered = ProcessImplicitLayersKey(key, normalPath, &otherJSONs, false);

  RegCloseKey(key);

#if ENABLED(RDOC_X64)
  {
    key = GetImplicitLayersKey(false, true);

    if(key)
    {
      // if we're on 64-bit, the layer isn't registered unless both keys are registered.
      thisRegistered &= ProcessImplicitLayersKey(key, wow6432Path, &otherJSONs, false);

      RegCloseKey(key);
    }
    else
    {
      flags = VulkanLayerFlags::NeedElevation | VulkanLayerFlags::RegisterAll;
      return true;
    }
  }
#endif

  flags = VulkanLayerFlags::NeedElevation | VulkanLayerFlags::RegisterAll;

  if(thisRegistered)
    flags |= VulkanLayerFlags::ThisInstallRegistered;

  if(!otherJSONs.empty())
    flags |= VulkanLayerFlags::OtherInstallsRegistered;

  // return true if any changes are needed
  return !otherJSONs.empty() || !thisRegistered;
}

void VulkanReplay::InstallVulkanLayer(bool systemLevel)
{
  HKEY key = GetImplicitLayersKey(true, false);

  const DWORD zero = 0;

  if(key)
  {
    std::wstring path = GetJSONPath(false);

    // this function will delete all non-matching renderdoc.json values, and return true if our own
    // is registered
    bool thisRegistered = ProcessImplicitLayersKey(key, path, NULL, true);

    if(!thisRegistered)
      RegSetValueExW(key, path.c_str(), 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero));

    RegCloseKey(key);
  }

// if we're a 64-bit process, update the 32-bit key
#if ENABLED(RDOC_X64)
  {
    key = GetImplicitLayersKey(true, true);

    if(key)
    {
      std::wstring path = GetJSONPath(true);

      // this function will delete all non-matching renderdoc.json values, and return true if our
      // own is registered
      bool thisRegistered = ProcessImplicitLayersKey(key, path, NULL, true);

      if(!thisRegistered)
        RegSetValueExW(key, path.c_str(), 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero));

      RegCloseKey(key);
    }
  }
#endif
}
<|endoftext|>


<commit_before>
#pragma once

// We use ostream for logging purposes.
#include <iostream>  // NOLINT(readability/streams)
#include <limits>
#include <string>
#include <type_traits>

#include "base/not_null.hpp"
#include "serialization/quantities.pb.h"

namespace principia {

using base::not_null;

namespace quantities {

template<int64_t LengthExponent, int64_t MassExponent, int64_t TimeExponent,
         int64_t CurrentExponent, int64_t TemperatureExponent,
         int64_t AmountExponent, int64_t LuminousIntensityExponent,
         int64_t WindingExponent, int64_t AngleExponent,
         int64_t SolidAngleExponent>
struct Dimensions;
template<typename D> class Quantity;

using NoDimensions = Dimensions<0, 0, 0, 0, 0, 0, 0, 0, 0, 0>;

// Base quantities
using Length            = Quantity<Dimensions<1, 0, 0, 0, 0, 0, 0, 0, 0, 0>>;
using Mass              = Quantity<Dimensions<0, 1, 0, 0, 0, 0, 0, 0, 0, 0>>;
using Time              = Quantity<Dimensions<0, 0, 1, 0, 0, 0, 0, 0, 0, 0>>;
using Current           = Quantity<Dimensions<0, 0, 0, 1, 0, 0, 0, 0, 0, 0>>;
using Temperature       = Quantity<Dimensions<0, 0, 0, 0, 1, 0, 0, 0, 0, 0>>;
using Amount            = Quantity<Dimensions<0, 0, 0, 0, 0, 1, 0, 0, 0, 0>>;
using LuminousIntensity = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 1, 0, 0, 0>>;
// Nonstandard; winding is a dimensionless quantity counting cycles, in order to
// strongly type the distinction between Frequency = Winding/Time and
// AngularFrequency = Angle/Time. We also strongly type angles.
using Winding           = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 0, 1, 0, 0>>;
using Angle             = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 0, 0, 1, 0>>;
using SolidAngle        = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 0, 0, 0, 1>>;

namespace internal {

template<typename Left, typename Right> struct ProductGenerator;
template<typename Left, typename Right> struct QuotientGenerator;
template <int n, typename Q, typename = void>
struct NthRootGenerator {};
template <typename T, int exponent, typename = void>
struct ExponentiationGenerator {};

template<typename Left, typename Right>
using Product = typename ProductGenerator<Left, Right>::Type;
template<typename Left, typename Right>
using Quotient = typename QuotientGenerator<Left, Right>::Type;

}  // namespace internal

// The result type of +, -, * and / on arguments of types |Left| and |Right|.
template<typename Left, typename Right>
using Sum = decltype(std::declval<Left>() = std::declval<Right>());
template<typename Left, typename Right = Left>
using Difference = decltype(std::declval<Left>() - std::declval<Right>());
template<typename Left, typename Right>
using Product = decltype(std::declval<Left>() * std::declval<Right>());
template<typename Left, typename Right>
using Quotient = decltype(std::declval<Left>() / std::declval<Right>());

// The result type of the derivative of a |Value|-valued function with respect
// to its |Argument|-valued argument.
template<typename Value, typename Argument>
using Derivative = Quotient<Difference<Value>, Difference<Argument>>;

// |Exponentiation<T, n>| is an alias for the following, where t is a value of
// type |T|:
//   The type of ( ... (t * t) * ... * t), with n factors, if n >= 1;
//   The type of t / ( ... (t * t) * ... * t), with n + 1 factors in the
//   denominator, if n < 1.
template<typename T, int exponent>
using Exponentiation =
    typename internal::ExponentiationGenerator<T, exponent>::Type;
template<typename Q>
using Square = Exponentiation<Q, 2>;
template<typename Q>
using Cube = Exponentiation<Q, 3>;

// |SquareRoot<T>| is only defined if |T| is an instance of |Quantity| with only
// even dimensions.  In that case, it is the unique instance |S| of |Quantity|
// such that |Product<S, S>| is |T|.
template<int n, typename Q>
using NthRoot = typename internal::NthRootGenerator<n, Q>::Type;
template<typename Q>
using SquareRoot = NthRoot<2, Q>;
template<typename Q>
using CubeRoot = NthRoot<3, Q>;

// Returns the base or derived SI Unit of |Q|.
// For instance, |SIUnit<Action>() == Joule * Second|.
template<typename Q>
constexpr Q SIUnit();
// Returns 1.
template<>
constexpr double SIUnit<double>();

template<typename LDimensions, typename RDimensions>
constexpr internal::Product<Quantity<LDimensions>, Quantity<RDimensions>>
operator*(Quantity<LDimensions> const&, Quantity<RDimensions> const&);
template<typename LDimensions, typename RDimensions>
constexpr internal::Quotient<Quantity<LDimensions>, Quantity<RDimensions>>
operator/(Quantity<LDimensions> const&, Quantity<RDimensions> const&);
template<typename RDimensions>
constexpr Quantity<RDimensions>
operator*(double, Quantity<RDimensions> const&);
template<typename RDimensions>
constexpr typename Quantity<RDimensions>::Inverse
operator/(double, Quantity<RDimensions> const&);

// Equivalent to |std::pow(x, exponent)| unless -3 ≤ x ≤ 3, in which case
// explicit specialization yields multiplications statically.
template<int exponent>
constexpr double Pow(double x);
template<int exponent, typename D>
constexpr Exponentiation<Quantity<D>, exponent> Pow(Quantity<D> const& x);

// Equivalent to |std::abs(x)|.
double Abs(double x);
template<typename D>
Quantity<D> Abs(Quantity<D> const& x);

template<typename D>
SquareRoot<Quantity<D>> Sqrt(Quantity<D> const& x);

template<typename D>
Angle ArcTan(Quantity<D> const& y, Quantity<D> const& x);

template<typename D>
bool IsFinite(Quantity<D> const& x);

std::string DebugString(
    double number,
    int precision = std::numeric_limits<double>::max_digits10);
template<typename D>
std::string DebugString(
    Quantity<D> const& quantity,
    int precision = std::numeric_limits<double>::max_digits10);

template<typename D>
std::ostream& operator<<(std::ostream& out, Quantity<D> const& quantity);

template<typename D>
class Quantity {
 public:
  using Dimensions = D;
  using Inverse = internal::Quotient<double, Quantity>;

  constexpr Quantity();
  ~Quantity() = default;

  constexpr Quantity operator+() const;
  constexpr Quantity operator-() const;
  constexpr Quantity operator+(Quantity const& right) const;
  constexpr Quantity operator-(Quantity const& right) const;

  constexpr Quantity operator*(double right) const;
  constexpr Quantity operator/(double right) const;

  Quantity& operator+=(Quantity const&);
  Quantity& operator-=(Quantity const&);
  Quantity& operator*=(double);
  Quantity& operator/=(double);

  constexpr bool operator>(Quantity const& right) const;
  constexpr bool operator<(Quantity const& right) const;
  constexpr bool operator>=(Quantity const& right) const;
  constexpr bool operator<=(Quantity const& right) const;
  constexpr bool operator==(Quantity const& right) const;
  constexpr bool operator!=(Quantity const& right) const;

  void WriteToMessage(not_null<serialization::Quantity*> message) const;
  static Quantity ReadFromMessage(serialization::Quantity const& message);

 private:
  explicit constexpr Quantity(double magnitude);
  double magnitude_;

  template<typename LDimensions, typename RDimensions>
  friend constexpr internal::Product<Quantity<LDimensions>,
                                     Quantity<RDimensions>> operator*(
      Quantity<LDimensions> const& left,
      Quantity<RDimensions> const& right);
  template<typename LDimensions, typename RDimensions>
  friend constexpr internal::Quotient<Quantity<LDimensions>,
                                      Quantity<RDimensions>> operator/(
      Quantity<LDimensions> const& left,
      Quantity<RDimensions> const& right);
  template<typename RDimensions>
  friend constexpr Quantity<RDimensions> operator*(
      double left,
      Quantity<RDimensions> const& right);
  template<typename RDimensions>
  friend constexpr typename Quantity<RDimensions>::Inverse operator/(
      double left,
      Quantity<RDimensions> const& right);

  template<typename Q>
  friend constexpr Q SIUnit();

  template<int exponent, typename BaseDimensions>
  friend constexpr Exponentiation<Quantity<BaseDimensions>, exponent> Pow(
      Quantity<BaseDimensions> const& x);

  template<typename E>
  friend Quantity<E> Abs(Quantity<E> const&);

  template<typename ArgumentDimensions>
  friend SquareRoot<Quantity<ArgumentDimensions>> Sqrt(
      Quantity<ArgumentDimensions> const& x);
  template<typename ArgumentDimensions>
  friend CubeRoot<Quantity<ArgumentDimensions>> Cbrt(
      Quantity<ArgumentDimensions> const& x);

  friend Angle ArcTan<>(Quantity<D> const& y, Quantity<D> const& x);
  friend bool IsFinite<>(Quantity<D> const& x);
  friend std::string DebugString<>(Quantity<D> const&, int);
};

// A type trait for testing if a type is a quantity.
template<typename T>
struct is_quantity : std::is_floating_point<T> {};
template<typename D>
struct is_quantity<Quantity<D>> : std::true_type {};

}  // namespace quantities
}  // namespace principia

#include "quantities/quantities_body.hpp"
<commit_msg>names<commit_after>
#pragma once

// We use ostream for logging purposes.
#include <iostream>  // NOLINT(readability/streams)
#include <limits>
#include <string>
#include <type_traits>

#include "base/not_null.hpp"
#include "serialization/quantities.pb.h"

namespace principia {

using base::not_null;

namespace quantities {

template<int64_t LengthExponent, int64_t MassExponent, int64_t TimeExponent,
         int64_t CurrentExponent, int64_t TemperatureExponent,
         int64_t AmountExponent, int64_t LuminousIntensityExponent,
         int64_t WindingExponent, int64_t AngleExponent,
         int64_t SolidAngleExponent>
struct Dimensions;
template<typename D> class Quantity;

using NoDimensions = Dimensions<0, 0, 0, 0, 0, 0, 0, 0, 0, 0>;

// Base quantities
using Length            = Quantity<Dimensions<1, 0, 0, 0, 0, 0, 0, 0, 0, 0>>;
using Mass              = Quantity<Dimensions<0, 1, 0, 0, 0, 0, 0, 0, 0, 0>>;
using Time              = Quantity<Dimensions<0, 0, 1, 0, 0, 0, 0, 0, 0, 0>>;
using Current           = Quantity<Dimensions<0, 0, 0, 1, 0, 0, 0, 0, 0, 0>>;
using Temperature       = Quantity<Dimensions<0, 0, 0, 0, 1, 0, 0, 0, 0, 0>>;
using Amount            = Quantity<Dimensions<0, 0, 0, 0, 0, 1, 0, 0, 0, 0>>;
using LuminousIntensity = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 1, 0, 0, 0>>;
// Nonstandard; winding is a dimensionless quantity counting cycles, in order to
// strongly type the distinction between Frequency = Winding/Time and
// AngularFrequency = Angle/Time. We also strongly type angles.
using Winding           = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 0, 1, 0, 0>>;
using Angle             = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 0, 0, 1, 0>>;
using SolidAngle        = Quantity<Dimensions<0, 0, 0, 0, 0, 0, 0, 0, 0, 1>>;

namespace internal {

template<typename Left, typename Right> struct ProductGenerator;
template<typename Left, typename Right> struct QuotientGenerator;
template <int n, typename Q, typename = void>
struct NthRootGenerator {};
template <typename T, int exponent, typename = void>
struct ExponentiationGenerator {};

template<typename Left, typename Right>
using Product = typename ProductGenerator<Left, Right>::Type;
template<typename Left, typename Right>
using Quotient = typename QuotientGenerator<Left, Right>::Type;

}  // namespace internal

// The result type of +, -, * and / on arguments of types |Left| and |Right|.
template<typename Left, typename Right>
using Sum = decltype(std::declval<Left>() = std::declval<Right>());
template<typename Left, typename Right = Left>
using Difference = decltype(std::declval<Left>() - std::declval<Right>());
template<typename Left, typename Right>
using Product = decltype(std::declval<Left>() * std::declval<Right>());
template<typename Left, typename Right>
using Quotient = decltype(std::declval<Left>() / std::declval<Right>());

// The result type of the derivative of a |Value|-valued function with respect
// to its |Argument|-valued argument.
template<typename Value, typename Argument>
using Derivative = Quotient<Difference<Value>, Difference<Argument>>;

// |Exponentiation<T, n>| is an alias for the following, where t is a value of
// type |T|:
//   The type of ( ... (t * t) * ... * t), with n factors, if n >= 1;
//   The type of t / ( ... (t * t) * ... * t), with n + 1 factors in the
//   denominator, if n < 1.
template<typename T, int exponent>
using Exponentiation =
    typename internal::ExponentiationGenerator<T, exponent>::Type;
template<typename Q>
using Square = Exponentiation<Q, 2>;
template<typename Q>
using Cube = Exponentiation<Q, 3>;

// |SquareRoot<T>| is only defined if |T| is an instance of |Quantity| with only
// even dimensions.  In that case, it is the unique instance |S| of |Quantity|
// such that |Product<S, S>| is |T|.
template<int n, typename Q>
using NthRoot = typename internal::NthRootGenerator<n, Q>::Type;
template<typename Q>
using SquareRoot = NthRoot<2, Q>;
template<typename Q>
using CubeRoot = NthRoot<3, Q>;

// Returns the base or derived SI Unit of |Q|.
// For instance, |SIUnit<Action>() == Joule * Second|.
template<typename Q>
constexpr Q SIUnit();
// Returns 1.
template<>
constexpr double SIUnit<double>();

template<typename LDimensions, typename RDimensions>
constexpr internal::Product<Quantity<LDimensions>, Quantity<RDimensions>>
operator*(Quantity<LDimensions> const&, Quantity<RDimensions> const&);
template<typename LDimensions, typename RDimensions>
constexpr internal::Quotient<Quantity<LDimensions>, Quantity<RDimensions>>
operator/(Quantity<LDimensions> const&, Quantity<RDimensions> const&);
template<typename RDimensions>
constexpr Quantity<RDimensions>
operator*(double, Quantity<RDimensions> const&);
template<typename RDimensions>
constexpr typename Quantity<RDimensions>::Inverse
operator/(double, Quantity<RDimensions> const&);

// Equivalent to |std::pow(x, exponent)| unless -3 ≤ x ≤ 3, in which case
// explicit specialization yields multiplications statically.
template<int exponent>
constexpr double Pow(double x);
template<int exponent, typename D>
constexpr Exponentiation<Quantity<D>, exponent> Pow(Quantity<D> const& x);

// Equivalent to |std::abs(x)|.
double Abs(double x);
template<typename D>
Quantity<D> Abs(Quantity<D> const& x);

template<typename D>
SquareRoot<Quantity<D>> Sqrt(Quantity<D> const& x);

template<typename D>
Angle ArcTan(Quantity<D> const& y, Quantity<D> const& x);

template<typename D>
bool IsFinite(Quantity<D> const& x);

std::string DebugString(
    double number,
    int precision = std::numeric_limits<double>::max_digits10);
template<typename D>
std::string DebugString(
    Quantity<D> const& quantity,
    int precision = std::numeric_limits<double>::max_digits10);

template<typename D>
std::ostream& operator<<(std::ostream& out, Quantity<D> const& quantity);

template<typename D>
class Quantity {
 public:
  using Dimensions = D;
  using Inverse = internal::Quotient<double, Quantity>;

  constexpr Quantity();
  ~Quantity() = default;

  constexpr Quantity operator+() const;
  constexpr Quantity operator-() const;
  constexpr Quantity operator+(Quantity const& right) const;
  constexpr Quantity operator-(Quantity const& right) const;

  constexpr Quantity operator*(double right) const;
  constexpr Quantity operator/(double right) const;

  Quantity& operator+=(Quantity const& right);
  Quantity& operator-=(Quantity const& right);
  Quantity& operator*=(double right);
  Quantity& operator/=(double right);

  constexpr bool operator>(Quantity const& right) const;
  constexpr bool operator<(Quantity const& right) const;
  constexpr bool operator>=(Quantity const& right) const;
  constexpr bool operator<=(Quantity const& right) const;
  constexpr bool operator==(Quantity const& right) const;
  constexpr bool operator!=(Quantity const& right) const;

  void WriteToMessage(not_null<serialization::Quantity*> message) const;
  static Quantity ReadFromMessage(serialization::Quantity const& message);

 private:
  explicit constexpr Quantity(double magnitude);
  double magnitude_;

  template<typename LDimensions, typename RDimensions>
  friend constexpr internal::Product<Quantity<LDimensions>,
                                     Quantity<RDimensions>> operator*(
      Quantity<LDimensions> const& left,
      Quantity<RDimensions> const& right);
  template<typename LDimensions, typename RDimensions>
  friend constexpr internal::Quotient<Quantity<LDimensions>,
                                      Quantity<RDimensions>> operator/(
      Quantity<LDimensions> const& left,
      Quantity<RDimensions> const& right);
  template<typename RDimensions>
  friend constexpr Quantity<RDimensions> operator*(
      double left,
      Quantity<RDimensions> const& right);
  template<typename RDimensions>
  friend constexpr typename Quantity<RDimensions>::Inverse operator/(
      double left,
      Quantity<RDimensions> const& right);

  template<typename Q>
  friend constexpr Q SIUnit();

  template<int exponent, typename BaseDimensions>
  friend constexpr Exponentiation<Quantity<BaseDimensions>, exponent> Pow(
      Quantity<BaseDimensions> const& x);

  template<typename E>
  friend Quantity<E> Abs(Quantity<E> const&);

  template<typename ArgumentDimensions>
  friend SquareRoot<Quantity<ArgumentDimensions>> Sqrt(
      Quantity<ArgumentDimensions> const& x);
  template<typename ArgumentDimensions>
  friend CubeRoot<Quantity<ArgumentDimensions>> Cbrt(
      Quantity<ArgumentDimensions> const& x);

  friend Angle ArcTan<>(Quantity<D> const& y, Quantity<D> const& x);
  friend bool IsFinite<>(Quantity<D> const& x);
  friend std::string DebugString<>(Quantity<D> const&, int);
};

// A type trait for testing if a type is a quantity.
template<typename T>
struct is_quantity : std::is_floating_point<T> {};
template<typename D>
struct is_quantity<Quantity<D>> : std::true_type {};

}  // namespace quantities
}  // namespace principia

#include "quantities/quantities_body.hpp"
<|endoftext|>


<commit_before>/* TRANSLATOR BALL::VIEW::PubChemDialog

		Necessary for lupdate.
*/

// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

#include <BALL/VIEW/DIALOGS/pubchemDialog.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/STRUCTURE/sdGenerator.h>
#include <BALL/FORMAT/SDFile.h>

#include <QtGui/QPushButton>
#include <QtGui/QTreeWidget>
#include <QtGui/QProgressBar>
#include <QtGui/QMessageBox>

#include <QtCore/QUrl>

#include <QtXml/QDomDocument>

#include <QtNetwork/QNetworkProxy>

#include <algorithm>

namespace BALL
{
	namespace VIEW
	{
		PubChemDialog::PubChemDialog(QWidget* parent, const char* name)
			: QDialog(parent),
				Ui_PubChemDialogData(),
				ModularWidget(name),
			  pcd_(0),
				action1_(0),
				action2_(0),
				progress_(0),
				downloader_(this)
		{
			#ifdef BALL_VIEW_DEBUG
				Log.error() << "new PubChemDialog " << this << std::endl;
			#endif

			setupUi(this);
			setObjectName(name);

			progress_ = new QProgressBar(queries);
			progress_->hide();

			// register the widget with the MainControl
			ModularWidget::registerWidget(this);

			add_button_ = buttonBox->addButton(tr("Add"), QDialogButtonBox::AcceptRole);
			QPushButton* clear = buttonBox->addButton(tr("Clear Results"), QDialogButtonBox::ResetRole);

			connect(generate_button, SIGNAL(clicked()), this, SLOT(generateButtonClicked()));
			connect(search_button, SIGNAL(clicked()), this, SLOT(queryPubChem()));
			connect(clear, SIGNAL(clicked()), this, SLOT(clearEntries()));
			connect(queries, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(switchView(QTreeWidgetItem*, int)));

			queries->setColumnCount(1);
			queries->headerItem()->setText(0, tr("Results"));
			//
			// TODO: re-enable the status bar...
		}

		PubChemDialog::~PubChemDialog()
		{
			delete pcd_;
#ifdef BALL_VIEW_DEBUG
			Log.error() << "deleting PubChemDialog " << this << std::endl;
#endif

			clearEntries();
		}

		void PubChemDialog::finished()
		{
			QTreeWidgetItem* item = queries->currentItem();
			// is this item connected with a system?
			if (sd_systems_.find(item) == sd_systems_.end()) return;

			hide();

			ParsedResult_& res = descriptions_.find(item)->second;

			System* org_system = sd_systems_.find(item)->second;
			System* new_system = new System(*org_system);

			new_system->setName(res.name);
			getMainControl()->insert(*new_system);
			getMainControl()->update(*new_system);
		}

		void PubChemDialog::clearEntries()
		{
			std::map<QTreeWidgetItem*, System*>::iterator it = sd_systems_.begin();
			for (; it != sd_systems_.end(); it++)
			{
				delete it->second;
			}

			it = original_systems_.begin();
			for (; it != original_systems_.end(); it++)
			{
				delete it->second;
			}

			sd_systems_.clear();
			original_systems_.clear();
			descriptions_.clear();
			queries->clear();
			sdwidget_->clear();
			text_field->clear();
		}

		void PubChemDialog::generateFromSMILES(const String& SMILES)
		{
			try
			{
				smiles_parser_.parse(SMILES);
			}
			catch(...)
			{
				setStatusbarText((String)tr("Invalid SMILES expression!"), true);
				return;
			}

			ParsedResult_ pr;
			pr.smiles = SMILES;
			pr.description = (String)tr("Generated from SMILES ")+SMILES;
			pr.name = SMILES;
			insert_(pr, 0, true);
		}

		void PubChemDialog::show()
		{
			QDialog::show();
			raise();
			add_button_->setDefault(false);
		}

		void PubChemDialog::generateButtonClicked()
		{
			generateFromSMILES(String(ascii(smiles_label->displayText())));
		}

		void PubChemDialog::switchView(QTreeWidgetItem* item, int /*column*/)
		{
			// is this item connected with a system?
			if (sd_systems_.find(item) != sd_systems_.end())
			{
				sdwidget_->plot(*sd_systems_[item], false);
			}

			// do we have a description for it?
			if (descriptions_.find(item) != descriptions_.end())
			{
				text_field->setText(QString(descriptions_[item].description.c_str()));
			}

			add_button_->setEnabled(true);
		}

		void PubChemDialog::queryPubChem()
		{
			String qt = ascii(pubchem_label->displayText());
			if (qt == "") return;

			if(pcd_) {
				delete pcd_;
			}

			pcd_ = new PubChemDownloader();

			File::createTemporaryFilename(downloader_.filename, ".sdf");

			getMainControl()->setStatusbarText(String(tr("Performing query...")));

			progress_->show();
			progress_->setMaximum(0);

			connect(pcd_, SIGNAL(downloadProgress(qint64, qint64)),
			        this, SLOT(updateDownloadProgress(qint64, qint64)));

			connect(pcd_, SIGNAL(downloadFinished(const QString&)),
			        this, SLOT(downloadFinished(const QString&)));

			downloader_.query = qt;

			downloader_.start();

			search_button->setEnabled(false);
		}

		void PubChemDialog::downloadFinished(const QString& filename)
		{
			disconnect(pcd_, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateDownloadProgress(qint64, qint64)));
			disconnect(pcd_, SIGNAL(downloadFinished(const QString&)), this, SLOT(downloadFinished(const QString&)));

			SDFile sdf;
			// now, try to read the SD File
			try {
				sdf.open(ascii(filename), std::ios::in);
			} catch(Exception::FileNotFound& e) {
				QMessageBox::critical(this, tr("Download failed"),
				                            tr("Could not download pubchem entries for") + " \"" + pubchem_label->displayText() + "\"");

				search_button->setEnabled(true);
				progress_->hide();

				return;
			}

			// iterate over the molecules in the SD File and build a system for each
			Size count = 0;

			sdf.enableAtoms();

			Molecule *current_molecule;
			std::deque<System*> sd_systems;
			do {
				try {
					current_molecule = sdf.read();
				} catch(Exception::ParseError& exn) {
					QMessageBox::critical(this, tr("Download failed"), tr("Error while parsing downloaded SD file. Aborting"));
					Log.error() << exn.getMessage() << std::endl;
					return;
				}

				if (current_molecule)
				{
					String qt = ascii(pubchem_label->displayText());
					System* new_system = new System(qt);

					new_system->insert(*current_molecule);

					if (current_molecule->hasProperty("PUBCHEM_IUPAC_NAME"))
					{
						current_molecule->setName(current_molecule->getProperty("PUBCHEM_IUPAC_NAME").toString());
					}

					sd_systems.push_back(new_system);
				}
				++count;
			} while(current_molecule && (count < 20)); // TODO: find a way to limit the *search* directly
			sdf.close();
			File::remove(ascii(filename));

			QTreeWidgetItem* new_query_result = new QTreeWidgetItem((QTreeWidget*)0,
																														 QStringList(pubchem_label->displayText()
																														             +" ("+QString::number(sd_systems.size())+ ")"));
			queries->insertTopLevelItem(0, new_query_result);
			queries->expandItem(new_query_result);

			QTreeWidgetItem* first_item = NULL;
			for (std::deque<System*>::iterator sys_it  = sd_systems.begin();
					                               sys_it != sd_systems.end(); ++sys_it)
			{
				ParsedResult_ pr;
				pr.name = (*sys_it)->beginMolecule()->getName();

				NamedPropertyIterator npi = (*sys_it)->beginMolecule()->beginNamedProperty();
				for (; npi != (*sys_it)->beginMolecule()->endNamedProperty(); ++npi)
				{
					String prop_name = npi->getName();
					if (prop_name.hasPrefix("PUBCHEM_"))
					{
						pr.description += String("")+prop_name.after("PUBCHEM_")+"
";
						pr.description += npi->toString()+"
";
					}
				}

				QTreeWidgetItem* current_item = new QTreeWidgetItem(new_query_result, QStringList(QString(pr.name.c_str())));
				descriptions_[current_item] = pr;

				sdwidget_->plot(**sys_it, false);
				sd_systems_[current_item] = *sys_it;

				queries->setCurrentItem(current_item);
				current_item->setSelected(true);
				switchView(current_item, 0);
				queries->setCurrentItem(current_item);
				current_item->setSelected(true);

				if (!first_item)
				{
					first_item = current_item;
				}
				queries->update();
			}

			if (first_item)
			{
				first_item->setSelected(true);
				queries->setCurrentItem(first_item);
				first_item->setSelected(true);
				switchView(first_item, 0);
			}

			search_button->setEnabled(true);
			progress_->hide();
		}

		void PubChemDialog::insert_(ParsedResult_ pr, QTreeWidgetItem* parent, bool plot)
		{
			QTreeWidgetItem* current_item = new QTreeWidgetItem(parent, QStringList(pr.name.c_str()));
			descriptions_[current_item] = pr;
			System S;

			try
			{
				smiles_parser_.parse(pr.smiles);
				S = smiles_parser_.getSystem();

				original_systems_[current_item] = new System(S);

				SDGenerator sdg;
				sdg.generateSD(S);
			}
			catch(...)
			{
				Log.info() << (String)tr("Secondary structure plotting failed");
			}

			if (plot)
			{
				sdwidget_->plot(S, false);
				switchView(current_item, 0);
			}

			sd_systems_[current_item] = new System(S);
			if (parent == 0)
			{
				QList<QTreeWidgetItem *> structure;
				structure.append(current_item);
				queries->insertTopLevelItems(0, structure);
			}

			queries->setCurrentItem(current_item);
			current_item->setSelected(true);
			queries->update();
		}

		void PubChemDialog::initializeWidget(MainControl&)
		{
			action1_ = insertMenuEntry(MainControl::FILE_OPEN, (String)tr("PubChem"), this, SLOT(show()), "Shortcut|File|Open|PubChem");
			setMenuHint((String)tr("Download a file from pubchem"));
			setIcon("actions/download-pubchem", true);

			action2_ = insertMenuEntry(MainControl::BUILD, (String)tr("Build from SMILES"), this, SLOT(show()), "Shortcut|Build|Build_from_SMILES");
			setMenuHint((String)tr("Create a structure from a SMILES expression"));
		}

		void PubChemDialog::checkMenu(MainControl& main_control)
		{
			bool busy = main_control.compositesAreLocked();
			action1_->setEnabled(!busy);
			action2_->setEnabled(!busy);
		}

		void PubChemDialog::updateDownloadProgress(qint64 done, qint64 total)
		{
			progress_->setMaximum(std::max(total, (qint64)0));
			progress_->setValue(done);
		}

		namespace PubChemDialogPrivate
		{
			DownloadHelper::DownloadHelper(PubChemDialog* parent)
				: QThread(),
					parent_(parent)
			{
			}

			void DownloadHelper::run()
			{
				parent_->pcd_->downloadSDF(query, filename, false);
			}
		}
	}
}
<commit_msg>Position progress bar in PubChemDialog more sensibly<commit_after>/* TRANSLATOR BALL::VIEW::PubChemDialog

		Necessary for lupdate.
*/

// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

#include <BALL/VIEW/DIALOGS/pubchemDialog.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/STRUCTURE/sdGenerator.h>
#include <BALL/FORMAT/SDFile.h>

#include <QtGui/QPushButton>
#include <QtGui/QTreeWidget>
#include <QtGui/QProgressBar>
#include <QtGui/QMessageBox>

#include <QtCore/QUrl>

#include <QtXml/QDomDocument>

#include <QtNetwork/QNetworkProxy>

#include <algorithm>

namespace BALL
{
	namespace VIEW
	{
		PubChemDialog::PubChemDialog(QWidget* parent, const char* name)
			: QDialog(parent),
				Ui_PubChemDialogData(),
				ModularWidget(name),
			  pcd_(0),
				action1_(0),
				action2_(0),
				progress_(0),
				downloader_(this)
		{
			#ifdef BALL_VIEW_DEBUG
				Log.error() << "new PubChemDialog " << this << std::endl;
			#endif

			setupUi(this);
			setObjectName(name);

			progress_ = new QProgressBar(queries);
			progress_->hide();

			// register the widget with the MainControl
			ModularWidget::registerWidget(this);

			add_button_ = buttonBox->addButton(tr("Add"), QDialogButtonBox::AcceptRole);
			QPushButton* clear = buttonBox->addButton(tr("Clear Results"), QDialogButtonBox::ResetRole);

			connect(generate_button, SIGNAL(clicked()), this, SLOT(generateButtonClicked()));
			connect(search_button, SIGNAL(clicked()), this, SLOT(queryPubChem()));
			connect(clear, SIGNAL(clicked()), this, SLOT(clearEntries()));
			connect(queries, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(switchView(QTreeWidgetItem*, int)));

			queries->setColumnCount(1);
			queries->headerItem()->setText(0, tr("Results"));
			//
			// TODO: re-enable the status bar...
		}

		PubChemDialog::~PubChemDialog()
		{
			delete pcd_;
#ifdef BALL_VIEW_DEBUG
			Log.error() << "deleting PubChemDialog " << this << std::endl;
#endif

			clearEntries();
		}

		void PubChemDialog::finished()
		{
			QTreeWidgetItem* item = queries->currentItem();
			// is this item connected with a system?
			if (sd_systems_.find(item) == sd_systems_.end()) return;

			hide();

			ParsedResult_& res = descriptions_.find(item)->second;

			System* org_system = sd_systems_.find(item)->second;
			System* new_system = new System(*org_system);

			new_system->setName(res.name);
			getMainControl()->insert(*new_system);
			getMainControl()->update(*new_system);
		}

		void PubChemDialog::clearEntries()
		{
			std::map<QTreeWidgetItem*, System*>::iterator it = sd_systems_.begin();
			for (; it != sd_systems_.end(); it++)
			{
				delete it->second;
			}

			it = original_systems_.begin();
			for (; it != original_systems_.end(); it++)
			{
				delete it->second;
			}

			sd_systems_.clear();
			original_systems_.clear();
			descriptions_.clear();
			queries->clear();
			sdwidget_->clear();
			text_field->clear();
		}

		void PubChemDialog::generateFromSMILES(const String& SMILES)
		{
			try
			{
				smiles_parser_.parse(SMILES);
			}
			catch(...)
			{
				setStatusbarText((String)tr("Invalid SMILES expression!"), true);
				return;
			}

			ParsedResult_ pr;
			pr.smiles = SMILES;
			pr.description = (String)tr("Generated from SMILES ")+SMILES;
			pr.name = SMILES;
			insert_(pr, 0, true);
		}

		void PubChemDialog::show()
		{
			QDialog::show();
			raise();
			add_button_->setDefault(false);
		}

		void PubChemDialog::generateButtonClicked()
		{
			generateFromSMILES(String(ascii(smiles_label->displayText())));
		}

		void PubChemDialog::switchView(QTreeWidgetItem* item, int /*column*/)
		{
			// is this item connected with a system?
			if (sd_systems_.find(item) != sd_systems_.end())
			{
				sdwidget_->plot(*sd_systems_[item], false);
			}

			// do we have a description for it?
			if (descriptions_.find(item) != descriptions_.end())
			{
				text_field->setText(QString(descriptions_[item].description.c_str()));
			}

			add_button_->setEnabled(true);
		}

		void PubChemDialog::queryPubChem()
		{
			String qt = ascii(pubchem_label->displayText());
			if (qt == "") return;

			if(pcd_) {
				delete pcd_;
			}

			pcd_ = new PubChemDownloader();

			File::createTemporaryFilename(downloader_.filename, ".sdf");

			getMainControl()->setStatusbarText(String(tr("Performing query...")));

			int progress_x = (queries->width() - progress_->width())/2;
			if (progress_x < 0) progress_x = 0;

			int progress_y = (queries->height() - progress_->height())/2;
			if (progress_y < 0) progress_y = 0;

			progress_->move(progress_x, progress_y);

			progress_->show();
			progress_->setMaximum(0);

			connect(pcd_, SIGNAL(downloadProgress(qint64, qint64)),
			        this, SLOT(updateDownloadProgress(qint64, qint64)));

			connect(pcd_, SIGNAL(downloadFinished(const QString&)),
			        this, SLOT(downloadFinished(const QString&)));

			downloader_.query = qt;

			downloader_.start();

			search_button->setEnabled(false);
		}

		void PubChemDialog::downloadFinished(const QString& filename)
		{
			disconnect(pcd_, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateDownloadProgress(qint64, qint64)));
			disconnect(pcd_, SIGNAL(downloadFinished(const QString&)), this, SLOT(downloadFinished(const QString&)));

			SDFile sdf;
			// now, try to read the SD File
			try {
				sdf.open(ascii(filename), std::ios::in);
			} catch(Exception::FileNotFound& e) {
				QMessageBox::critical(this, tr("Download failed"),
				                            tr("Could not download pubchem entries for") + " \"" + pubchem_label->displayText() + "\"");

				search_button->setEnabled(true);
				progress_->hide();

				return;
			}

			// iterate over the molecules in the SD File and build a system for each
			Size count = 0;

			sdf.enableAtoms();

			Molecule *current_molecule;
			std::deque<System*> sd_systems;
			do {
				try {
					current_molecule = sdf.read();
				} catch(Exception::ParseError& exn) {
					QMessageBox::critical(this, tr("Download failed"), tr("Error while parsing downloaded SD file. Aborting"));
					Log.error() << exn.getMessage() << std::endl;
					return;
				}

				if (current_molecule)
				{
					String qt = ascii(pubchem_label->displayText());
					System* new_system = new System(qt);

					new_system->insert(*current_molecule);

					if (current_molecule->hasProperty("PUBCHEM_IUPAC_NAME"))
					{
						current_molecule->setName(current_molecule->getProperty("PUBCHEM_IUPAC_NAME").toString());
					}

					sd_systems.push_back(new_system);
				}
				++count;
			} while(current_molecule && (count < 20)); // TODO: find a way to limit the *search* directly
			sdf.close();
			File::remove(ascii(filename));

			QTreeWidgetItem* new_query_result = new QTreeWidgetItem((QTreeWidget*)0,
																														 QStringList(pubchem_label->displayText()
																														             +" ("+QString::number(sd_systems.size())+ ")"));
			queries->insertTopLevelItem(0, new_query_result);
			queries->expandItem(new_query_result);

			QTreeWidgetItem* first_item = NULL;
			for (std::deque<System*>::iterator sys_it  = sd_systems.begin();
					                               sys_it != sd_systems.end(); ++sys_it)
			{
				ParsedResult_ pr;
				pr.name = (*sys_it)->beginMolecule()->getName();

				NamedPropertyIterator npi = (*sys_it)->beginMolecule()->beginNamedProperty();
				for (; npi != (*sys_it)->beginMolecule()->endNamedProperty(); ++npi)
				{
					String prop_name = npi->getName();
					if (prop_name.hasPrefix("PUBCHEM_"))
					{
						pr.description += String("")+prop_name.after("PUBCHEM_")+"
";
						pr.description += npi->toString()+"
";
					}
				}

				QTreeWidgetItem* current_item = new QTreeWidgetItem(new_query_result, QStringList(QString(pr.name.c_str())));
				descriptions_[current_item] = pr;

				sdwidget_->plot(**sys_it, false);
				sd_systems_[current_item] = *sys_it;

				queries->setCurrentItem(current_item);
				current_item->setSelected(true);
				switchView(current_item, 0);
				queries->setCurrentItem(current_item);
				current_item->setSelected(true);

				if (!first_item)
				{
					first_item = current_item;
				}
				queries->update();
			}

			if (first_item)
			{
				first_item->setSelected(true);
				queries->setCurrentItem(first_item);
				first_item->setSelected(true);
				switchView(first_item, 0);
			}

			search_button->setEnabled(true);
			progress_->hide();
		}

		void PubChemDialog::insert_(ParsedResult_ pr, QTreeWidgetItem* parent, bool plot)
		{
			QTreeWidgetItem* current_item = new QTreeWidgetItem(parent, QStringList(pr.name.c_str()));
			descriptions_[current_item] = pr;
			System S;

			try
			{
				smiles_parser_.parse(pr.smiles);
				S = smiles_parser_.getSystem();

				original_systems_[current_item] = new System(S);

				SDGenerator sdg;
				sdg.generateSD(S);
			}
			catch(...)
			{
				Log.info() << (String)tr("Secondary structure plotting failed");
			}

			if (plot)
			{
				sdwidget_->plot(S, false);
				switchView(current_item, 0);
			}

			sd_systems_[current_item] = new System(S);
			if (parent == 0)
			{
				QList<QTreeWidgetItem *> structure;
				structure.append(current_item);
				queries->insertTopLevelItems(0, structure);
			}

			queries->setCurrentItem(current_item);
			current_item->setSelected(true);
			queries->update();
		}

		void PubChemDialog::initializeWidget(MainControl&)
		{
			action1_ = insertMenuEntry(MainControl::FILE_OPEN, (String)tr("PubChem"), this, SLOT(show()), "Shortcut|File|Open|PubChem");
			setMenuHint((String)tr("Download a file from pubchem"));
			setIcon("actions/download-pubchem", true);

			action2_ = insertMenuEntry(MainControl::BUILD, (String)tr("Build from SMILES"), this, SLOT(show()), "Shortcut|Build|Build_from_SMILES");
			setMenuHint((String)tr("Create a structure from a SMILES expression"));
		}

		void PubChemDialog::checkMenu(MainControl& main_control)
		{
			bool busy = main_control.compositesAreLocked();
			action1_->setEnabled(!busy);
			action2_->setEnabled(!busy);
		}

		void PubChemDialog::updateDownloadProgress(qint64 done, qint64 total)
		{
			progress_->setMaximum(std::max(total, (qint64)0));
			progress_->setValue(done);
		}

		namespace PubChemDialogPrivate
		{
			DownloadHelper::DownloadHelper(PubChemDialog* parent)
				: QThread(),
					parent_(parent)
			{
			}

			void DownloadHelper::run()
			{
				parent_->pcd_->downloadSDF(query, filename, false);
			}
		}
	}
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2008 by Daniel Schwen   *
 *   daniel@schwen.de   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <iostream>

#include "simconf.h"
#include "element.h"
#include "material.h"
#include "sample_wire.h"
#include "sample_burried_wire.h"
#include "ion.h"
#include "trim.h"
#include "invert.h"
#include <r250.h>

#include "functions.h"

using namespace std;

int main(int argc, char *argv[])
{
  char fname[200];
  if( argc != 8 )
  {
    fprintf( stderr, "syntax:\nmytrim_wire basename Eion[eV] angle[deg] numpka zpka mpka diameter(nm)\n" );
    return 1;
  }

  double epka  = atof(argv[2]);
  double theta = atof(argv[3]) * M_PI/180.0; // 0 = parallel to wire
  int numpka  = atoi(argv[4]);
  int   zpka  = atoi(argv[5]);
  double mpka  = atof(argv[6]);
  double diameter  = 10.0*atof(argv[7]);
  double length  = 10000.0;
  bool burried = true;

  // seed randomnumber generator from system entropy pool
  FILE *urand = fopen( "/dev/random", "r" );
  int seed;
  fread( &seed, sizeof(int), 1, urand );
  fclose( urand );
  r250_init( seed<0 ? -seed : seed ); // random generator goes haywire with neg. seed

  // initialize global parameter structure and read data tables from file
  simconf = new simconfType;

  // initialize sample structure
  sampleWire *sample;
  if( burried )
    sample = new sampleBurriedWire( diameter, diameter, length );
  else
  {
    sample = new sampleWire( diameter, diameter, length );
    sample->bc[2] = sampleWire::CUT;
  }

  // initialize trim engine for the sample
/*  const int z1 = 31;
  const int z2 = 33;
  trimVacMap *trim = new trimVacMap( sample, z1, z2 ); // GaAs*/
  trimBase *trim = new trimBase( sample );

  materialBase *material;
  elementBase *element;

  // Si
  material = new materialBase( 2.329 ); // rho
  element = new elementBase;
  element->z = 14; // Si
  element->m = 28.0;
  element->t = 1.0;
  material->element.push_back( element );
  material->prepare(); // all materials added
  sample->material.push_back( material ); // add material to sample

  // SiO2 (material[1] for the cover layer in SampleBurriedWire)
  material = new materialBase( 2.634 ); // rho
  element = new elementBase;
  element->z = 14; // Si
  element->m = 28.0;
  element->t = 1.0;
  material->element.push_back( element );
  element = new elementBase;
  element->z = 8; // O
  element->m = 16.0;
  element->t = 2.0;
  material->element.push_back( element );
  material->prepare(); // all materials added
  sample->material.push_back( material ); // add material to sample

  // create a FIFO for recoils
  queue<ionBase*> recoils;

  double norm;
  double jmp = 2.7; // diffusion jump distance
  int jumps;
  double dif[3];

  //snprintf( fname, 199, "%s.Erec", argv[1] );
  //FILE *erec = fopen( fname, "wt" );

  //snprintf( fname, 199, "%s.dist", argv[1] );
  //FILE *rdist = fopen( fname, "wt" );

  ionBase *pka;

  const int mx = 20, my = 20;
  int imap[mx][my][3];
  for( int e = 0; e < 3; e++ )
    for( int x = 0; x < mx; x++ )
      for( int y = 0; y < my; y++ )
        imap[x][y][e] = 0;

  // 10000 ions
  for( int n = 0; n < numpka; n++ )
  {
    if( n % 1000 == 0 ) fprintf( stderr, "pka #%d\n", n+1 );

    pka = new ionBase;
    pka->gen = 0; // generation (0 = PKA)
    pka->tag = -1;
    pka->md = 0;
    pka->z1 = zpka; // S
    pka->m1 = mpka;
    pka->e  = epka;

    pka->dir[0] = 0.0;
    pka->dir[1] = sin( theta );
    pka->dir[2] = cos( theta );

    v_norm( pka->dir );

    if( burried )
    {
      // cannot anticipate the straggling in the burrial layer, thus have to shoot onto a big surface
      // TODO: take theta into account!
      pka->pos[0] = dr250() * ( 2.0*length + sample->w[0] ) - ( length + 0.5 * sample->w[0] ) ;
      pka->pos[1] = dr250() * ( 2.0*length + sample->w[1] ) - ( length + 0.5 * sample->w[1] ) ;
      pka->pos[2] = -250.0; // overcoat thickness
    }
    else
    {
      if( theta == 0.0 )
      {
        // 0 degrees => start on top of wire!
        pka->pos[2] = 0;
        do
        {
          pka->pos[0] = dr250() * sample->w[0];
          pka->pos[1] = dr250() * sample->w[1];
        } while( sample->lookupMaterial(pka->pos ) == 0 );
      }
      else
      {
        // start on side _or_ top!
        double vpos[3], t;
        do
        {
          do
          {
            vpos[0] = dr250() * sample->w[0];
            vpos[1] = 0.0;
            vpos[2] = ( dr250() * ( length + cot(theta)*diameter ) ) - cot(theta)*diameter;

            t = ( 1.0 - sqrt( 1.0 - sqr( 2*vpos[0]/diameter - 1.0 ) ) ) * diameter/(2.0*pka->dir[1]);

            // if we start beyond wire length (that would be inside the substrate) then retry
          } while( t*pka->dir[2] + vpos[2] >= length );

          // if first intersection with cylinder is at z<0 then check if we hit the top face instead
          if( t*pka->dir[2] + vpos[2] < 0.0 )
            t = -vpos[2]/pka->dir[2];

          // start PKA at calculated intersection point
          for( int i = 0; i < 3; i++ )
              pka->pos[i] = t*pka->dir[i] + vpos[i];

        } while( sample->lookupMaterial(pka->pos ) == 0 );
      }
    }
    cout << "START " << pka->pos[0] << ' ' << pka->pos[1] << ' ' << pka->pos[2] << ' ' << endl;
    continue;

    pka->set_ef();
    recoils.push( pka );

    while( !recoils.empty() )
    {
      pka = recoils.front();
      recoils.pop();
      sample->averages( pka );

      // do ion analysis/processing BEFORE the cascade here

      if( pka->z1 == zpka  )
      {
        //printf(  "p1 %f\t%f\t%f\n", pka->pos[0], pka->pos[1], pka->pos[2] );
      }

      // follow this ion's trajectory and store recoils
      // printf( "%f\t%d\n", pka->e, pka->z1 );
      trim->trim( pka, recoils );

      // do ion analysis/processing AFTER the cascade here

      // ion is still in sample
      if(  sample->lookupMaterial( pka->pos ) != 0 )
      {
        int x, y;
        x = ( ( pka->pos[0] * mx ) / sample->w[0] );
        y = ( ( pka->pos[1] * my ) / sample->w[1] );
        x -= int(x/mx) * mx;
        y -= int(y/my) * my;

        // keep track of interstitials for the two constituents
/*        if( pka->z1 == z1 ) imap[x][y][0]++;
        else if( pka->z1 == z2 ) imap[x][y][1]++;
        else imap[x][y][2]++; // the PKAs*/
      }

      // done with this recoil
      delete pka;
    }
  }

//   char *elnam[3] = { "Ga", "As", "ion" };

//   FILE *intf, *vacf, *netf;
//   for( int e = 0; e < 3; e++ )
//   {
//     snprintf( fname, 199, "%s.%s.int", argv[1], elnam[e] );
//     intf = fopen( fname, "wt" );
//     snprintf( fname, 199, "%s.%s.vac", argv[1], elnam[e] );
//     vacf = fopen( fname, "wt" );
//     snprintf( fname, 199, "%s.%s.net", argv[1], elnam[e] );
//     netf = fopen( fname, "wt" );
//
//     for( int y = 0; y <= my; y++ )
//     {
//       for( int x = 0; x <= mx; x++ )
//       {
//         fprintf( intf, "%d %d %d\n", x, y, (x<mx && y<my) ? imap[x][y][e] : 0 );
//         fprintf( vacf, "%d %d %d\n", x, y, (x<mx && y<my) ? trim->vmap[x][y][e] : 0 );
//         fprintf( netf, "%d %d %d\n", x, y, (x<mx && y<my) ? ( imap[x][y][e] - trim->vmap[x][y][e] ) : 0 );
//       }
//       fprintf( intf, "\n" );
//       fprintf( vacf, "\n" );
//       fprintf( netf, "\n" );
//     }
//
//     fclose( intf );
//     fclose( vacf );
//     fclose( netf );
//   }

  return EXIT_SUCCESS;
}
<commit_msg>replace cot by 1/tan<commit_after>/***************************************************************************
 *   Copyright (C) 2008 by Daniel Schwen   *
 *   daniel@schwen.de   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <iostream>

#include "simconf.h"
#include "element.h"
#include "material.h"
#include "sample_wire.h"
#include "sample_burried_wire.h"
#include "ion.h"
#include "trim.h"
#include "invert.h"
#include <r250.h>

#include "functions.h"

using namespace std;

int main(int argc, char *argv[])
{
  char fname[200];
  if( argc != 8 )
  {
    fprintf( stderr, "syntax:\nmytrim_wire basename Eion[eV] angle[deg] numpka zpka mpka diameter(nm)\n" );
    return 1;
  }

  double epka  = atof(argv[2]);
  double theta = atof(argv[3]) * M_PI/180.0; // 0 = parallel to wire
  int numpka  = atoi(argv[4]);
  int   zpka  = atoi(argv[5]);
  double mpka  = atof(argv[6]);
  double diameter  = 10.0*atof(argv[7]);
  double length  = 10000.0;
  bool burried = true;

  // seed randomnumber generator from system entropy pool
  FILE *urand = fopen( "/dev/random", "r" );
  int seed;
  fread( &seed, sizeof(int), 1, urand );
  fclose( urand );
  r250_init( seed<0 ? -seed : seed ); // random generator goes haywire with neg. seed

  // initialize global parameter structure and read data tables from file
  simconf = new simconfType;

  // initialize sample structure
  sampleWire *sample;
  if( burried )
    sample = new sampleBurriedWire( diameter, diameter, length );
  else
  {
    sample = new sampleWire( diameter, diameter, length );
    sample->bc[2] = sampleWire::CUT;
  }

  // initialize trim engine for the sample
/*  const int z1 = 31;
  const int z2 = 33;
  trimVacMap *trim = new trimVacMap( sample, z1, z2 ); // GaAs*/
  trimBase *trim = new trimBase( sample );

  materialBase *material;
  elementBase *element;

  // Si
  material = new materialBase( 2.329 ); // rho
  element = new elementBase;
  element->z = 14; // Si
  element->m = 28.0;
  element->t = 1.0;
  material->element.push_back( element );
  material->prepare(); // all materials added
  sample->material.push_back( material ); // add material to sample

  // SiO2 (material[1] for the cover layer in SampleBurriedWire)
  material = new materialBase( 2.634 ); // rho
  element = new elementBase;
  element->z = 14; // Si
  element->m = 28.0;
  element->t = 1.0;
  material->element.push_back( element );
  element = new elementBase;
  element->z = 8; // O
  element->m = 16.0;
  element->t = 2.0;
  material->element.push_back( element );
  material->prepare(); // all materials added
  sample->material.push_back( material ); // add material to sample

  // create a FIFO for recoils
  queue<ionBase*> recoils;

  double norm;
  double jmp = 2.7; // diffusion jump distance
  int jumps;
  double dif[3];

  //snprintf( fname, 199, "%s.Erec", argv[1] );
  //FILE *erec = fopen( fname, "wt" );

  //snprintf( fname, 199, "%s.dist", argv[1] );
  //FILE *rdist = fopen( fname, "wt" );

  ionBase *pka;

  const int mx = 20, my = 20;
  int imap[mx][my][3];
  for( int e = 0; e < 3; e++ )
    for( int x = 0; x < mx; x++ )
      for( int y = 0; y < my; y++ )
        imap[x][y][e] = 0;

  // 10000 ions
  for( int n = 0; n < numpka; n++ )
  {
    if( n % 1000 == 0 ) fprintf( stderr, "pka #%d\n", n+1 );

    pka = new ionBase;
    pka->gen = 0; // generation (0 = PKA)
    pka->tag = -1;
    pka->md = 0;
    pka->z1 = zpka; // S
    pka->m1 = mpka;
    pka->e  = epka;

    pka->dir[0] = 0.0;
    pka->dir[1] = sin( theta );
    pka->dir[2] = cos( theta );

    v_norm( pka->dir );

    if( burried )
    {
      // cannot anticipate the straggling in the burrial layer, thus have to shoot onto a big surface
      // TODO: take theta into account!
      pka->pos[0] = dr250() * ( 2.0*length + sample->w[0] ) - ( length + 0.5 * sample->w[0] ) ;
      pka->pos[1] = dr250() * ( 2.0*length + sample->w[1] ) - ( length + 0.5 * sample->w[1] ) ;
      pka->pos[2] = -250.0; // overcoat thickness
    }
    else
    {
      if( theta == 0.0 )
      {
        // 0 degrees => start on top of wire!
        pka->pos[2] = 0;
        do
        {
          pka->pos[0] = dr250() * sample->w[0];
          pka->pos[1] = dr250() * sample->w[1];
        } while( sample->lookupMaterial(pka->pos ) == 0 );
      }
      else
      {
        // start on side _or_ top!
        double vpos[3], t;
        do
        {
          do
          {
            vpos[0] = dr250() * sample->w[0];
            vpos[1] = 0.0;
            vpos[2] = ( dr250() * ( length + diameter/tan(theta) ) ) - diameter/tan(theta);

            t = ( 1.0 - sqrt( 1.0 - sqr( 2*vpos[0]/diameter - 1.0 ) ) ) * diameter/(2.0*pka->dir[1]);

            // if we start beyond wire length (that would be inside the substrate) then retry
          } while( t*pka->dir[2] + vpos[2] >= length );

          // if first intersection with cylinder is at z<0 then check if we hit the top face instead
          if( t*pka->dir[2] + vpos[2] < 0.0 )
            t = -vpos[2]/pka->dir[2];

          // start PKA at calculated intersection point
          for( int i = 0; i < 3; i++ )
              pka->pos[i] = t*pka->dir[i] + vpos[i];

        } while( sample->lookupMaterial(pka->pos ) == 0 );
      }
    }
    cout << "START " << pka->pos[0] << ' ' << pka->pos[1] << ' ' << pka->pos[2] << ' ' << endl;
    continue;

    pka->set_ef();
    recoils.push( pka );

    while( !recoils.empty() )
    {
      pka = recoils.front();
      recoils.pop();
      sample->averages( pka );

      // do ion analysis/processing BEFORE the cascade here

      if( pka->z1 == zpka  )
      {
        //printf(  "p1 %f\t%f\t%f\n", pka->pos[0], pka->pos[1], pka->pos[2] );
      }

      // follow this ion's trajectory and store recoils
      // printf( "%f\t%d\n", pka->e, pka->z1 );
      trim->trim( pka, recoils );

      // do ion analysis/processing AFTER the cascade here

      // ion is still in sample
      if(  sample->lookupMaterial( pka->pos ) != 0 )
      {
        int x, y;
        x = ( ( pka->pos[0] * mx ) / sample->w[0] );
        y = ( ( pka->pos[1] * my ) / sample->w[1] );
        x -= int(x/mx) * mx;
        y -= int(y/my) * my;

        // keep track of interstitials for the two constituents
/*        if( pka->z1 == z1 ) imap[x][y][0]++;
        else if( pka->z1 == z2 ) imap[x][y][1]++;
        else imap[x][y][2]++; // the PKAs*/
      }

      // done with this recoil
      delete pka;
    }
  }

//   char *elnam[3] = { "Ga", "As", "ion" };

//   FILE *intf, *vacf, *netf;
//   for( int e = 0; e < 3; e++ )
//   {
//     snprintf( fname, 199, "%s.%s.int", argv[1], elnam[e] );
//     intf = fopen( fname, "wt" );
//     snprintf( fname, 199, "%s.%s.vac", argv[1], elnam[e] );
//     vacf = fopen( fname, "wt" );
//     snprintf( fname, 199, "%s.%s.net", argv[1], elnam[e] );
//     netf = fopen( fname, "wt" );
//
//     for( int y = 0; y <= my; y++ )
//     {
//       for( int x = 0; x <= mx; x++ )
//       {
//         fprintf( intf, "%d %d %d\n", x, y, (x<mx && y<my) ? imap[x][y][e] : 0 );
//         fprintf( vacf, "%d %d %d\n", x, y, (x<mx && y<my) ? trim->vmap[x][y][e] : 0 );
//         fprintf( netf, "%d %d %d\n", x, y, (x<mx && y<my) ? ( imap[x][y][e] - trim->vmap[x][y][e] ) : 0 );
//       }
//       fprintf( intf, "\n" );
//       fprintf( vacf, "\n" );
//       fprintf( netf, "\n" );
//     }
//
//     fclose( intf );
//     fclose( vacf );
//     fclose( netf );
//   }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright (c) 2022 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <memory>
#include <string>
#include <list>
#include "./tracy/Tracy.hpp"
#include "./tracy/client/TracyProfiler.hpp"
#include "./tracy/client/TracyScoped.hpp"
#include "../common/python_helper.hh"

class TracyProfiler final : public python_helper::Singleton<TracyProfiler> {
  using ScopedZonePtr = std::shared_ptr<tracy::ScopedZone>;

  std::list<ScopedZonePtr> scoped_zones_;
public:
  inline void push_event(const std::string& funcname, const std::string& filename, int lineno) noexcept {
    scoped_zones_.push_back(std::make_shared<tracy::ScopedZone>(
          lineno, filename.c_str(), filename.size(), funcname.c_str(), funcname.size(),
          nullptr, 0, TRACY_CALLSTACK, true));
  }

  inline void pop_event() noexcept {
    if (!scoped_zones_.empty())
      scoped_zones_.pop_back();
  }

  inline void frame_event() noexcept { FrameMarkNamed("Tracy.Python"); }
};

static int _pprofile_tracefunc(PyObject* obj, PyFrameObject* frame, int what, PyObject* arg) {
  switch (what) {
  case PyTrace_CALL:
    {
      PyCodeObject* funccode = frame->f_code;
      auto [funcname, filename] = python_helper::get_from_call(funccode);
      TracyProfiler::get_instance().push_event(funcname, filename, funccode->co_firstlineno);
    } break;
  case PyTrace_C_CALL:
    if (PyCFunction_Check(arg)) {
      PyCFunctionObject* fn = reinterpret_cast<PyCFunctionObject*>(arg);
      auto [funcname, filename] = python_helper::get_from_ccall(fn);
      TracyProfiler::get_instance().push_event(funcname, filename, 0);
    } break;
  case PyTrace_RETURN:
  case PyTrace_C_RETURN:
  case PyTrace_C_EXCEPTION:
    TracyProfiler::get_instance().pop_event(); break;
  default: break;
  }
  return 0;
}

static PyObject* _pprofile_enable(PyObject* obj, PyObject* args) {
  (void)obj, (void)args;

  PyEval_SetProfile(_pprofile_tracefunc, nullptr);
  Py_RETURN_NONE;
}

static PyObject* _pprofile_disable(PyObject* obj, PyObject* args) {
  (void)obj, (void)args;

  PyEval_SetProfile(nullptr, nullptr);
  Py_RETURN_NONE;
}

static PyObject* _pprofile_frame(PyObject* obj, PyObject* args) {
  (void)obj, (void)args;

  TracyProfiler::get_instance().frame_event();
  Py_RETURN_NONE;
}

PyMODINIT_FUNC PyInit_cpprofile() {
  static PyMethodDef _pprofile_methods[] = {
    {"enable", _pprofile_enable, METH_NOARGS, "cpprofile.enable() -> None"},
    {"disable", _pprofile_disable, METH_NOARGS, "cpprofile.disable() -> None"},
    {"frame", _pprofile_frame, METH_NOARGS, "cpprofile.frame() -> None"},
    {nullptr},
  };
  static PyModuleDef _pprofile_module = {
    PyModuleDef_HEAD_INIT,
    "cpprofile", // m_name
    "CXX profile with Tracy binding", // m_doc
    -1, // m_size
    _pprofile_methods, // m_methods
    nullptr, // m_reload
    nullptr, // m_traverse
    nullptr, // m_clear
    nullptr, // m_free
  };

  return PyModule_Create(&_pprofile_module);
}
<commit_msg>:construction: chore(profile): updated the profile with tracy<commit_after>// Copyright (c) 2022 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <memory>
#include <string>
#include <list>
#include "./tracy/Tracy.hpp"
#include "./tracy/client/TracyProfiler.hpp"
#include "./tracy/client/TracyScoped.hpp"
#include "../common/common.hh"
#include "../common/python_helper.hh"

class TracyProfiler final : public common::Singleton<TracyProfiler> {
  using ScopedZonePtr = std::shared_ptr<tracy::ScopedZone>;

  std::list<ScopedZonePtr> scoped_zones_;
public:
  inline void push_event(const std::string& funcname, const std::string& filename, int lineno) noexcept {
    scoped_zones_.push_back(std::make_shared<tracy::ScopedZone>(
          lineno, filename.c_str(), filename.size(), funcname.c_str(), funcname.size(),
          nullptr, 0, TRACY_CALLSTACK, true));
  }

  inline void pop_event() noexcept {
    if (!scoped_zones_.empty())
      scoped_zones_.pop_back();
  }

  inline void frame_event() noexcept { FrameMarkNamed("Tracy.Python"); }
};

static int _pprofile_tracefunc(PyObject* obj, PyFrameObject* frame, int what, PyObject* arg) {
  switch (what) {
  case PyTrace_CALL:
    {
      PyCodeObject* funccode = frame->f_code;
      auto [funcname, filename] = python_helper::get_from_call(funccode);
      TracyProfiler::get_instance().push_event(funcname, filename, funccode->co_firstlineno);
    } break;
  case PyTrace_C_CALL:
    if (PyCFunction_Check(arg)) {
      PyCFunctionObject* fn = reinterpret_cast<PyCFunctionObject*>(arg);
      auto [funcname, filename] = python_helper::get_from_ccall(fn);
      TracyProfiler::get_instance().push_event(funcname, filename, 0);
    } break;
  case PyTrace_RETURN:
  case PyTrace_C_RETURN:
    TracyProfiler::get_instance().pop_event();
    break;
  case PyTrace_C_EXCEPTION:
    if (PyCFunction_Check(arg))
      TracyProfiler::get_instance().pop_event();
    break;
  default: break;
  }
  return 0;
}

static PyObject* _pprofile_enable(PyObject* obj, PyObject* args) {
  (void)obj, (void)args;

  PyEval_SetProfile(_pprofile_tracefunc, nullptr);
  Py_RETURN_NONE;
}

static PyObject* _pprofile_disable(PyObject* obj, PyObject* args) {
  (void)obj, (void)args;

  PyEval_SetProfile(nullptr, nullptr);
  Py_RETURN_NONE;
}

static PyObject* _pprofile_frame(PyObject* obj, PyObject* args) {
  (void)obj, (void)args;

  TracyProfiler::get_instance().frame_event();
  Py_RETURN_NONE;
}

PyMODINIT_FUNC PyInit_cpprofile() {
  static PyMethodDef _pprofile_methods[] = {
    {"enable", _pprofile_enable, METH_NOARGS, "cpprofile.enable() -> None"},
    {"disable", _pprofile_disable, METH_NOARGS, "cpprofile.disable() -> None"},
    {"frame", _pprofile_frame, METH_NOARGS, "cpprofile.frame() -> None"},
    {nullptr},
  };
  static PyModuleDef _pprofile_module = {
    PyModuleDef_HEAD_INIT,
    "cpprofile", // m_name
    "CXX profile with Tracy binding", // m_doc
    -1, // m_size
    _pprofile_methods, // m_methods
    nullptr, // m_reload
    nullptr, // m_traverse
    nullptr, // m_clear
    nullptr, // m_free
  };

  return PyModule_Create(&_pprofile_module);
}
<|endoftext|>


<commit_before><commit_msg>Remove empty file.<commit_after><|endoftext|>