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

#include "GLFWOSPRayWindow.h"
#include <iostream>
#include <stdexcept>

#include <imgui.h>
#include "imgui/imgui_impl_glfw_gl3.h"

GLFWOSPRayWindow *GLFWOSPRayWindow::activeWindow = nullptr;

GLFWOSPRayWindow::GLFWOSPRayWindow(const ospcommon::vec2i &windowSize,
                                   const ospcommon::box3f &worldBounds,
                                   OSPModel model,
                                   OSPRenderer renderer)
    : windowSize(windowSize),
      worldBounds(worldBounds),
      model(model),
      renderer(renderer)
{
  if (activeWindow != nullptr)
    throw std::runtime_error("Cannot create more than one GLFWOSPRayWindow!");

  activeWindow = this;

  // initialize GLFW
  if (!glfwInit())
    throw std::runtime_error("Failed to initialize GLFW!");

  // create GLFW window
  glfwWindow = glfwCreateWindow(
      windowSize.x, windowSize.y, "OSPRay Tutorial", NULL, NULL);

  if (!glfwWindow) {
    glfwTerminate();
    throw std::runtime_error("Failed to create GLFW window!");
  }

  // make the window's context current
  glfwMakeContextCurrent(glfwWindow);

  ImGui_ImplGlfwGL3_Init(glfwWindow, true);

  // set initial OpenGL state
  glEnable(GL_TEXTURE_2D);
  glDisable(GL_LIGHTING);

  // create OpenGL frame buffer texture
  glGenTextures(1, &framebufferTexture);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, framebufferTexture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  // set GLFW callbacks
  glfwSetFramebufferSizeCallback(
      glfwWindow, [](GLFWwindow *, int newWidth, int newHeight) {
        activeWindow->reshape(ospcommon::vec2i{newWidth, newHeight});
      });

  glfwSetCursorPosCallback(glfwWindow, [](GLFWwindow *, double x, double y) {
    ImGuiIO &io = ImGui::GetIO();
    if (!io.WantCaptureMouse)
      activeWindow->motion(ospcommon::vec2f{float(x), float(y)});
  });

  glfwSetKeyCallback(glfwWindow,
                     [](GLFWwindow *, int key, int, int action, int) {
                       if (action == GLFW_PRESS) {
                         switch (key) {
                         case GLFW_KEY_G:
                           activeWindow->showUi = !(activeWindow->showUi);
                           break;
                         }
                       }
                     });

  // OSPRay setup

  // set the model on the renderer
  ospSetObject(renderer, "model", model);

  // create the arcball camera model
  arcballCamera = std::unique_ptr<ArcballCamera>(
      new ArcballCamera(worldBounds, windowSize));

  // create camera
  camera = ospNewCamera("perspective");
  ospSetf(camera, "aspect", windowSize.x / float(windowSize.y));

  ospSet3f(camera,
           "pos",
           arcballCamera->eyePos().x,
           arcballCamera->eyePos().y,
           arcballCamera->eyePos().z);
  ospSet3f(camera,
           "dir",
           arcballCamera->lookDir().x,
           arcballCamera->lookDir().y,
           arcballCamera->lookDir().z);
  ospSet3f(camera,
           "up",
           arcballCamera->upDir().x,
           arcballCamera->upDir().y,
           arcballCamera->upDir().z);

  ospCommit(camera);

  // set camera on the renderer
  ospSetObject(renderer, "camera", camera);

  // finally, commit the renderer
  ospCommit(renderer);

  // trigger window reshape events with current window size
  glfwGetFramebufferSize(glfwWindow, &this->windowSize.x, &this->windowSize.y);
  reshape(this->windowSize);
}

GLFWOSPRayWindow::~GLFWOSPRayWindow()
{
  ImGui_ImplGlfwGL3_Shutdown();
  // cleanly terminate GLFW
  glfwTerminate();
}

GLFWOSPRayWindow *GLFWOSPRayWindow::getActiveWindow()
{
  return activeWindow;
}

OSPModel GLFWOSPRayWindow::getModel()
{
  return model;
}

void GLFWOSPRayWindow::setModel(OSPModel newModel)
{
  model = newModel;

  // set the model on the renderer
  ospSetObject(renderer, "model", model);

  // commit the renderer
  ospCommit(renderer);

  // clear frame buffer
  ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM);
}

void GLFWOSPRayWindow::clearFrameBuffer()
{
  ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM);
}

void GLFWOSPRayWindow::registerDisplayCallback(
    std::function<void(GLFWOSPRayWindow *)> callback)
{
  displayCallback = callback;
}

void GLFWOSPRayWindow::registerImGuiCallback(std::function<void()> callback)
{
  uiCallback = callback;
}

void GLFWOSPRayWindow::mainLoop()
{
  // continue until the user closes the window
  startNewOSPRayFrame();

  while (!glfwWindowShouldClose(glfwWindow)) {
    ImGui_ImplGlfwGL3_NewFrame();

    display();

    // poll and process events
    glfwPollEvents();
  }

  waitOnOSPRayFrame();
  if (currentFrame != nullptr)
    ospRelease(currentFrame);
}

void GLFWOSPRayWindow::reshape(const ospcommon::vec2i &newWindowSize)
{
  windowSize = newWindowSize;

  // release the current frame buffer, if it exists
  if (framebuffer)
    ospRelease(framebuffer);

  // create new frame buffer
  framebuffer = ospNewFrameBuffer(reinterpret_cast<osp_vec2i &>(windowSize),
                                  OSP_FB_SRGBA,
                                  OSP_FB_COLOR | OSP_FB_ACCUM);

  // reset OpenGL viewport and orthographic projection
  glViewport(0, 0, windowSize.x, windowSize.y);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0.0, windowSize.x, 0.0, windowSize.y, -1.0, 1.0);

  // update camera
  arcballCamera->updateWindowSize(windowSize);

  ospSetf(camera, "aspect", windowSize.x / float(windowSize.y));
  ospCommit(camera);
}

void GLFWOSPRayWindow::motion(const ospcommon::vec2f &position)
{
  static ospcommon::vec2f previousMouse(-1);

  const ospcommon::vec2f mouse(position.x, position.y);
  if (previousMouse != ospcommon::vec2f(-1)) {
    const bool leftDown =
        glfwGetMouseButton(glfwWindow, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
    const bool rightDown =
        glfwGetMouseButton(glfwWindow, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;
    const bool middleDown =
        glfwGetMouseButton(glfwWindow, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS;
    const ospcommon::vec2f prev = previousMouse;

    bool cameraChanged = leftDown || rightDown || middleDown;

    if (leftDown) {
      const ospcommon::vec2f mouseFrom(
          ospcommon::clamp(prev.x * 2.f / windowSize.x - 1.f, -1.f, 1.f),
          ospcommon::clamp(prev.y * 2.f / windowSize.y - 1.f, -1.f, 1.f));
      const ospcommon::vec2f mouseTo(
          ospcommon::clamp(mouse.x * 2.f / windowSize.x - 1.f, -1.f, 1.f),
          ospcommon::clamp(mouse.y * 2.f / windowSize.y - 1.f, -1.f, 1.f));
      arcballCamera->rotate(mouseFrom, mouseTo);
    } else if (rightDown) {
      arcballCamera->zoom(mouse.y - prev.y);
    } else if (middleDown) {
      arcballCamera->pan(ospcommon::vec2f(mouse.x - prev.x, prev.y - mouse.y));
    }

    if (cameraChanged) {
      ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM);

      ospSetf(camera, "aspect", windowSize.x / float(windowSize.y));
      ospSet3f(camera,
               "pos",
               arcballCamera->eyePos().x,
               arcballCamera->eyePos().y,
               arcballCamera->eyePos().z);
      ospSet3f(camera,
               "dir",
               arcballCamera->lookDir().x,
               arcballCamera->lookDir().y,
               arcballCamera->lookDir().z);
      ospSet3f(camera,
               "up",
               arcballCamera->upDir().x,
               arcballCamera->upDir().y,
               arcballCamera->upDir().z);

      ospCommit(camera);
    }
  }

  previousMouse = mouse;
}

void GLFWOSPRayWindow::display()
{
  // clock used to compute frame rate
  static auto displayStart = std::chrono::high_resolution_clock::now();

  if (showUi && uiCallback) {
    ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize;
    ImGui::Begin(
        "Tutorial Controls (press 'g' to hide / show)", nullptr, flags);
    uiCallback();
    ImGui::End();
  }

  // if a display callback has been registered, call it
  if (displayCallback) {
    displayCallback(this);
  }

  static bool firstFrame = true;

  if (firstFrame || ospIsReady(currentFrame)) {
    waitOnOSPRayFrame();

    // map OSPRay frame buffer, update OpenGL texture with its contents, then
    // unmap
    uint32_t *fb = (uint32_t *)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR);

    glBindTexture(GL_TEXTURE_2D, framebufferTexture);
    glTexImage2D(GL_TEXTURE_2D,
                 0,
                 GL_RGBA,
                 windowSize.x,
                 windowSize.y,
                 0,
                 GL_RGBA,
                 GL_UNSIGNED_BYTE,
                 fb);

    ospUnmapFrameBuffer(fb, framebuffer);

    startNewOSPRayFrame();

    firstFrame = false;

    // display frame rate in window title
    auto displayEnd = std::chrono::high_resolution_clock::now();
    auto durationMilliseconds =
        std::chrono::duration_cast<std::chrono::milliseconds>(displayEnd -
                                                              displayStart);
    displayStart = displayEnd;

    const float frameRate = 1000.f / float(durationMilliseconds.count());

    std::stringstream windowTitle;
    windowTitle << "OSPRay: " << std::setprecision(3) << frameRate << " fps";
    glfwSetWindowTitle(glfwWindow, windowTitle.str().c_str());
  }

  // clear current OpenGL color buffer
  glClear(GL_COLOR_BUFFER_BIT);

  // render textured quad with OSPRay frame buffer contents
  glBegin(GL_QUADS);

  glTexCoord2f(0.f, 0.f);
  glVertex2f(0.f, 0.f);

  glTexCoord2f(0.f, 1.f);
  glVertex2f(0.f, windowSize.y);

  glTexCoord2f(1.f, 1.f);
  glVertex2f(windowSize.x, windowSize.y);

  glTexCoord2f(1.f, 0.f);
  glVertex2f(windowSize.x, 0.f);

  glEnd();

  if (showUi && uiCallback) {
    ImGui::Render();
  }

  // swap buffers
  glfwSwapBuffers(glfwWindow);
}

void GLFWOSPRayWindow::startNewOSPRayFrame()
{
  if (currentFrame != nullptr)
    ospRelease(currentFrame);

  currentFrame =
      ospRenderFrameAsync(framebuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM);
}

void GLFWOSPRayWindow::waitOnOSPRayFrame()
{
  if (currentFrame != nullptr) {
    ospWait(currentFrame, OSP_FRAME_FINISHED);
  }
}<commit_msg>implemnt 'q' to quit interactive tutorials<commit_after>// ======================================================================== //
// Copyright 2018-2019 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "GLFWOSPRayWindow.h"
#include <iostream>
#include <stdexcept>

#include <imgui.h>
#include "imgui/imgui_impl_glfw_gl3.h"

GLFWOSPRayWindow *GLFWOSPRayWindow::activeWindow = nullptr;

static bool g_quitNextFrame = false;

GLFWOSPRayWindow::GLFWOSPRayWindow(const ospcommon::vec2i &windowSize,
                                   const ospcommon::box3f &worldBounds,
                                   OSPModel model,
                                   OSPRenderer renderer)
    : windowSize(windowSize),
      worldBounds(worldBounds),
      model(model),
      renderer(renderer)
{
  if (activeWindow != nullptr)
    throw std::runtime_error("Cannot create more than one GLFWOSPRayWindow!");

  activeWindow = this;

  // initialize GLFW
  if (!glfwInit())
    throw std::runtime_error("Failed to initialize GLFW!");

  // create GLFW window
  glfwWindow = glfwCreateWindow(
      windowSize.x, windowSize.y, "OSPRay Tutorial", NULL, NULL);

  if (!glfwWindow) {
    glfwTerminate();
    throw std::runtime_error("Failed to create GLFW window!");
  }

  // make the window's context current
  glfwMakeContextCurrent(glfwWindow);

  ImGui_ImplGlfwGL3_Init(glfwWindow, true);

  // set initial OpenGL state
  glEnable(GL_TEXTURE_2D);
  glDisable(GL_LIGHTING);

  // create OpenGL frame buffer texture
  glGenTextures(1, &framebufferTexture);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, framebufferTexture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  // set GLFW callbacks
  glfwSetFramebufferSizeCallback(
      glfwWindow, [](GLFWwindow *, int newWidth, int newHeight) {
        activeWindow->reshape(ospcommon::vec2i{newWidth, newHeight});
      });

  glfwSetCursorPosCallback(glfwWindow, [](GLFWwindow *, double x, double y) {
    ImGuiIO &io = ImGui::GetIO();
    if (!io.WantCaptureMouse)
      activeWindow->motion(ospcommon::vec2f{float(x), float(y)});
  });

  glfwSetKeyCallback(glfwWindow,
                     [](GLFWwindow *, int key, int, int action, int) {
                       if (action == GLFW_PRESS) {
                         switch (key) {
                         case GLFW_KEY_G:
                           activeWindow->showUi = !(activeWindow->showUi);
                           break;
                         case GLFW_KEY_Q:
                           g_quitNextFrame = true;
                           break;
                         }
                       }
                     });

  // OSPRay setup

  // set the model on the renderer
  ospSetObject(renderer, "model", model);

  // create the arcball camera model
  arcballCamera = std::unique_ptr<ArcballCamera>(
      new ArcballCamera(worldBounds, windowSize));

  // create camera
  camera = ospNewCamera("perspective");
  ospSetf(camera, "aspect", windowSize.x / float(windowSize.y));

  ospSet3f(camera,
           "pos",
           arcballCamera->eyePos().x,
           arcballCamera->eyePos().y,
           arcballCamera->eyePos().z);
  ospSet3f(camera,
           "dir",
           arcballCamera->lookDir().x,
           arcballCamera->lookDir().y,
           arcballCamera->lookDir().z);
  ospSet3f(camera,
           "up",
           arcballCamera->upDir().x,
           arcballCamera->upDir().y,
           arcballCamera->upDir().z);

  ospCommit(camera);

  // set camera on the renderer
  ospSetObject(renderer, "camera", camera);

  // finally, commit the renderer
  ospCommit(renderer);

  // trigger window reshape events with current window size
  glfwGetFramebufferSize(glfwWindow, &this->windowSize.x, &this->windowSize.y);
  reshape(this->windowSize);
}

GLFWOSPRayWindow::~GLFWOSPRayWindow()
{
  ImGui_ImplGlfwGL3_Shutdown();
  // cleanly terminate GLFW
  glfwTerminate();
}

GLFWOSPRayWindow *GLFWOSPRayWindow::getActiveWindow()
{
  return activeWindow;
}

OSPModel GLFWOSPRayWindow::getModel()
{
  return model;
}

void GLFWOSPRayWindow::setModel(OSPModel newModel)
{
  model = newModel;

  // set the model on the renderer
  ospSetObject(renderer, "model", model);

  // commit the renderer
  ospCommit(renderer);

  // clear frame buffer
  ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM);
}

void GLFWOSPRayWindow::clearFrameBuffer()
{
  ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM);
}

void GLFWOSPRayWindow::registerDisplayCallback(
    std::function<void(GLFWOSPRayWindow *)> callback)
{
  displayCallback = callback;
}

void GLFWOSPRayWindow::registerImGuiCallback(std::function<void()> callback)
{
  uiCallback = callback;
}

void GLFWOSPRayWindow::mainLoop()
{
  // continue until the user closes the window
  startNewOSPRayFrame();

  while (!glfwWindowShouldClose(glfwWindow) && !g_quitNextFrame) {
    ImGui_ImplGlfwGL3_NewFrame();

    display();

    // poll and process events
    glfwPollEvents();
  }

  waitOnOSPRayFrame();
  if (currentFrame != nullptr)
    ospRelease(currentFrame);
}

void GLFWOSPRayWindow::reshape(const ospcommon::vec2i &newWindowSize)
{
  windowSize = newWindowSize;

  // release the current frame buffer, if it exists
  if (framebuffer)
    ospRelease(framebuffer);

  // create new frame buffer
  framebuffer = ospNewFrameBuffer(reinterpret_cast<osp_vec2i &>(windowSize),
                                  OSP_FB_SRGBA,
                                  OSP_FB_COLOR | OSP_FB_ACCUM);

  // reset OpenGL viewport and orthographic projection
  glViewport(0, 0, windowSize.x, windowSize.y);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0.0, windowSize.x, 0.0, windowSize.y, -1.0, 1.0);

  // update camera
  arcballCamera->updateWindowSize(windowSize);

  ospSetf(camera, "aspect", windowSize.x / float(windowSize.y));
  ospCommit(camera);
}

void GLFWOSPRayWindow::motion(const ospcommon::vec2f &position)
{
  static ospcommon::vec2f previousMouse(-1);

  const ospcommon::vec2f mouse(position.x, position.y);
  if (previousMouse != ospcommon::vec2f(-1)) {
    const bool leftDown =
        glfwGetMouseButton(glfwWindow, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
    const bool rightDown =
        glfwGetMouseButton(glfwWindow, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;
    const bool middleDown =
        glfwGetMouseButton(glfwWindow, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS;
    const ospcommon::vec2f prev = previousMouse;

    bool cameraChanged = leftDown || rightDown || middleDown;

    if (leftDown) {
      const ospcommon::vec2f mouseFrom(
          ospcommon::clamp(prev.x * 2.f / windowSize.x - 1.f, -1.f, 1.f),
          ospcommon::clamp(prev.y * 2.f / windowSize.y - 1.f, -1.f, 1.f));
      const ospcommon::vec2f mouseTo(
          ospcommon::clamp(mouse.x * 2.f / windowSize.x - 1.f, -1.f, 1.f),
          ospcommon::clamp(mouse.y * 2.f / windowSize.y - 1.f, -1.f, 1.f));
      arcballCamera->rotate(mouseFrom, mouseTo);
    } else if (rightDown) {
      arcballCamera->zoom(mouse.y - prev.y);
    } else if (middleDown) {
      arcballCamera->pan(ospcommon::vec2f(mouse.x - prev.x, prev.y - mouse.y));
    }

    if (cameraChanged) {
      ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM);

      ospSetf(camera, "aspect", windowSize.x / float(windowSize.y));
      ospSet3f(camera,
               "pos",
               arcballCamera->eyePos().x,
               arcballCamera->eyePos().y,
               arcballCamera->eyePos().z);
      ospSet3f(camera,
               "dir",
               arcballCamera->lookDir().x,
               arcballCamera->lookDir().y,
               arcballCamera->lookDir().z);
      ospSet3f(camera,
               "up",
               arcballCamera->upDir().x,
               arcballCamera->upDir().y,
               arcballCamera->upDir().z);

      ospCommit(camera);
    }
  }

  previousMouse = mouse;
}

void GLFWOSPRayWindow::display()
{
  // clock used to compute frame rate
  static auto displayStart = std::chrono::high_resolution_clock::now();

  if (showUi && uiCallback) {
    ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize;
    ImGui::Begin(
        "Tutorial Controls (press 'g' to hide / show)", nullptr, flags);
    uiCallback();
    ImGui::End();
  }

  // if a display callback has been registered, call it
  if (displayCallback) {
    displayCallback(this);
  }

  static bool firstFrame = true;

  if (firstFrame || ospIsReady(currentFrame)) {
    waitOnOSPRayFrame();

    // map OSPRay frame buffer, update OpenGL texture with its contents, then
    // unmap
    uint32_t *fb = (uint32_t *)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR);

    glBindTexture(GL_TEXTURE_2D, framebufferTexture);
    glTexImage2D(GL_TEXTURE_2D,
                 0,
                 GL_RGBA,
                 windowSize.x,
                 windowSize.y,
                 0,
                 GL_RGBA,
                 GL_UNSIGNED_BYTE,
                 fb);

    ospUnmapFrameBuffer(fb, framebuffer);

    startNewOSPRayFrame();

    firstFrame = false;

    // display frame rate in window title
    auto displayEnd = std::chrono::high_resolution_clock::now();
    auto durationMilliseconds =
        std::chrono::duration_cast<std::chrono::milliseconds>(displayEnd -
                                                              displayStart);
    displayStart = displayEnd;

    const float frameRate = 1000.f / float(durationMilliseconds.count());

    std::stringstream windowTitle;
    windowTitle << "OSPRay: " << std::setprecision(3) << frameRate << " fps";
    glfwSetWindowTitle(glfwWindow, windowTitle.str().c_str());
  }

  // clear current OpenGL color buffer
  glClear(GL_COLOR_BUFFER_BIT);

  // render textured quad with OSPRay frame buffer contents
  glBegin(GL_QUADS);

  glTexCoord2f(0.f, 0.f);
  glVertex2f(0.f, 0.f);

  glTexCoord2f(0.f, 1.f);
  glVertex2f(0.f, windowSize.y);

  glTexCoord2f(1.f, 1.f);
  glVertex2f(windowSize.x, windowSize.y);

  glTexCoord2f(1.f, 0.f);
  glVertex2f(windowSize.x, 0.f);

  glEnd();

  if (showUi && uiCallback) {
    ImGui::Render();
  }

  // swap buffers
  glfwSwapBuffers(glfwWindow);
}

void GLFWOSPRayWindow::startNewOSPRayFrame()
{
  if (currentFrame != nullptr)
    ospRelease(currentFrame);

  currentFrame =
      ospRenderFrameAsync(framebuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM);
}

void GLFWOSPRayWindow::waitOnOSPRayFrame()
{
  if (currentFrame != nullptr) {
    ospWait(currentFrame, OSP_FRAME_FINISHED);
  }
}<|endoftext|>


<commit_before>// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

#pragma once

#if !defined(RXCPP_OPERATORS_RX_TAKE_UNTIL_HPP)
#define RXCPP_OPERATORS_RX_TAKE_UNTIL_HPP

#include "../rx-includes.hpp"

namespace rxcpp {

namespace operators {

namespace detail {

template<class T, class Observable, class TriggerObservable>
struct take_until : public operator_base<T>
{
    typedef typename std::decay<Observable>::type source_type;
    typedef typename std::decay<TriggerObservable>::type trigger_source_type;
    struct values
    {
        values(source_type s, trigger_source_type t)
            : source(std::move(s))
            , trigger(std::move(t))
        {
        }
        source_type source;
        trigger_source_type trigger;
    };
    values initial;

    take_until(source_type s, trigger_source_type t)
        : initial(std::move(s), std::move(t))
    {
    }

    struct mode
    {
        enum type {
            taking,
            clear,
            triggered,
            errored,
            stopped
        };
    };

    template<class Subscriber>
    void on_subscribe(const Subscriber& s) {

        typedef Subscriber output_type;
        struct state_type
            : public std::enable_shared_from_this<state_type>
            , public values
        {
            state_type(const values& i, const output_type& oarg)
                : values(i)
                , mode_value(mode::taking)
                , busy(0)
                , out(oarg)
            {
            }
            mutable std::atomic<typename mode::type> mode_value;
            mutable std::atomic<int> busy;
            mutable std::mutex error_lock;
            mutable std::exception_ptr exception;
            output_type out;
        };
        // take a copy of the values for each subscription
        auto state = std::shared_ptr<state_type>(new state_type(initial, s));

        struct activity
        {
            const std::shared_ptr<state_type>& st;
            ~activity() {
                if (--st->busy == 0 && st->mode_value > mode::clear) {
                    // need to finish
                    if (st->mode_value < mode::stopped && ++st->busy == 1) {
                        // this is the finish owner
                        auto fin = st->mode_value.exchange(mode::stopped);
                        if (fin == mode::triggered) {
                            st->out.on_completed();
                        } else if (fin == mode::errored) {
                            std::unique_lock<std::mutex> guard(st->error_lock);
                            st->out.on_error(st->exception);
                        }
                    }
                }
            }
            explicit activity(const std::shared_ptr<state_type>& st)
                : st(st)
            {
                ++st->busy;
            }

        };

        state->trigger.subscribe(
        // share subscription lifetime
            state->out,
        // on_next
            [state](const typename trigger_source_type::value_type&) {
                activity finisher(state);
                typename mode::type v = state->mode_value;
                if (v != mode::taking) {return;}
                state->mode_value.compare_exchange_strong(v, mode::triggered);
            },
        // on_error
            [state](std::exception_ptr e) {
                activity finisher(state);
                std::unique_lock<std::mutex> guard(state->error_lock);
                typename mode::type v = state->mode_value;
                if (v != mode::taking) {return;}
                if (state->mode_value.compare_exchange_strong(v, mode::errored)) {
                    state->exception = e;
                }
            },
        // on_completed
            [state]() {
                activity finisher(state);
                typename mode::type v = state->mode_value;
                if (v != mode::taking) {return;}
                state->mode_value.compare_exchange_strong(v, mode::clear);
            }
        );

        state->source.subscribe(
        // share subscription lifetime
            state->out,
        // on_next
            [state](T t) {
                activity finisher(state);
                if (state->mode_value < mode::triggered) {
                    state->out.on_next(t);
                }
            },
        // on_error
            [state](std::exception_ptr e) {
                activity finisher(state);
                std::unique_lock<std::mutex> guard(state->error_lock);
                typename mode::type v = state->mode_value;
                if (v < mode::triggered) {return;}
                if (state->mode_value.compare_exchange_strong(v, mode::errored)) {
                    state->exception = e;
                }
            },
        // on_completed
            [state]() {
                activity finisher(state);
                typename mode::type v = state->mode_value;
                if (v < mode::triggered) {return;}
                state->mode_value.compare_exchange_strong(v, mode::triggered);
            }
        );
    }
};

template<class TriggerObservable>
class take_until_factory
{
    typedef typename std::decay<TriggerObservable>::type trigger_source_type;
    trigger_source_type trigger_source;
public:
    take_until_factory(trigger_source_type t) : trigger_source(std::move(t)) {}
    template<class Observable>
    auto operator()(Observable&& source)
        ->      observable<typename std::decay<Observable>::type::value_type,   take_until<typename std::decay<Observable>::type::value_type, Observable, trigger_source_type>> {
        return  observable<typename std::decay<Observable>::type::value_type,   take_until<typename std::decay<Observable>::type::value_type, Observable, trigger_source_type>>(
                                                                                take_until<typename std::decay<Observable>::type::value_type, Observable, trigger_source_type>(std::forward<Observable>(source), trigger_source));
    }
};

}

template<class TriggerObservable>
auto take_until(TriggerObservable&& t)
    ->      detail::take_until_factory<TriggerObservable> {
    return  detail::take_until_factory<TriggerObservable>(std::forward<TriggerObservable>(t));
}

}

}

#endif
<commit_msg>separate lifetime of trigger subscription<commit_after>// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

#pragma once

#if !defined(RXCPP_OPERATORS_RX_TAKE_UNTIL_HPP)
#define RXCPP_OPERATORS_RX_TAKE_UNTIL_HPP

#include "../rx-includes.hpp"

namespace rxcpp {

namespace operators {

namespace detail {

template<class T, class Observable, class TriggerObservable>
struct take_until : public operator_base<T>
{
    typedef typename std::decay<Observable>::type source_type;
    typedef typename std::decay<TriggerObservable>::type trigger_source_type;
    struct values
    {
        values(source_type s, trigger_source_type t)
            : source(std::move(s))
            , trigger(std::move(t))
        {
        }
        source_type source;
        trigger_source_type trigger;
    };
    values initial;

    take_until(source_type s, trigger_source_type t)
        : initial(std::move(s), std::move(t))
    {
    }

    struct mode
    {
        enum type {
            taking,
            clear,
            triggered,
            errored,
            stopped
        };
    };

    template<class Subscriber>
    void on_subscribe(const Subscriber& s) {

        typedef Subscriber output_type;
        struct state_type
            : public std::enable_shared_from_this<state_type>
            , public values
        {
            state_type(const values& i, const output_type& oarg)
                : values(i)
                , mode_value(mode::taking)
                , busy(0)
                , out(oarg)
            {
            }
            mutable std::atomic<typename mode::type> mode_value;
            mutable std::atomic<int> busy;
            mutable std::mutex error_lock;
            mutable std::exception_ptr exception;
            output_type out;
        };
        // take a copy of the values for each subscription
        auto state = std::shared_ptr<state_type>(new state_type(initial, s));

        struct activity
        {
            const std::shared_ptr<state_type>& st;
            ~activity() {
                if (--st->busy == 0 && st->mode_value > mode::clear) {
                    // need to finish
                    if (st->mode_value < mode::stopped && ++st->busy == 1) {
                        // this is the finish owner
                        auto fin = st->mode_value.exchange(mode::stopped);
                        if (fin == mode::triggered) {
                            st->out.on_completed();
                        } else if (fin == mode::errored) {
                            std::unique_lock<std::mutex> guard(st->error_lock);
                            st->out.on_error(st->exception);
                        }
                    }
                }
            }
            explicit activity(const std::shared_ptr<state_type>& st)
                : st(st)
            {
                ++st->busy;
            }

        };

        composite_subscription trigger_lifetime;
        state->out.add(trigger_lifetime);

        state->trigger.subscribe(
        // share parts of subscription
            state->out,
        // new lifetime
            trigger_lifetime,
        // on_next
            [state](const typename trigger_source_type::value_type&) {
                activity finisher(state);
                typename mode::type v = state->mode_value;
                if (v != mode::taking) {return;}
                state->mode_value.compare_exchange_strong(v, mode::triggered);
            },
        // on_error
            [state](std::exception_ptr e) {
                activity finisher(state);
                std::unique_lock<std::mutex> guard(state->error_lock);
                typename mode::type v = state->mode_value;
                if (v != mode::taking) {return;}
                if (state->mode_value.compare_exchange_strong(v, mode::errored)) {
                    state->exception = e;
                }
            },
        // on_completed
            [state]() {
                activity finisher(state);
                typename mode::type v = state->mode_value;
                if (v != mode::taking) {return;}
                state->mode_value.compare_exchange_strong(v, mode::clear);
            }
        );

        state->source.subscribe(
        // share subscription lifetime
            state->out,
        // on_next
            [state](T t) {
                //
                // everything is crafted to minimize the overhead of this function.
                //
                activity finisher(state);
                if (state->mode_value < mode::triggered) {
                    state->out.on_next(t);
                }
            },
        // on_error
            [state](std::exception_ptr e) {
                activity finisher(state);
                std::unique_lock<std::mutex> guard(state->error_lock);
                typename mode::type v = state->mode_value;
                if (v < mode::triggered) {return;}
                if (state->mode_value.compare_exchange_strong(v, mode::errored)) {
                    state->exception = e;
                }
            },
        // on_completed
            [state]() {
                activity finisher(state);
                typename mode::type v = state->mode_value;
                if (v < mode::triggered) {return;}
                state->mode_value.compare_exchange_strong(v, mode::triggered);
            }
        );
    }
};

template<class TriggerObservable>
class take_until_factory
{
    typedef typename std::decay<TriggerObservable>::type trigger_source_type;
    trigger_source_type trigger_source;
public:
    take_until_factory(trigger_source_type t) : trigger_source(std::move(t)) {}
    template<class Observable>
    auto operator()(Observable&& source)
        ->      observable<typename std::decay<Observable>::type::value_type,   take_until<typename std::decay<Observable>::type::value_type, Observable, trigger_source_type>> {
        return  observable<typename std::decay<Observable>::type::value_type,   take_until<typename std::decay<Observable>::type::value_type, Observable, trigger_source_type>>(
                                                                                take_until<typename std::decay<Observable>::type::value_type, Observable, trigger_source_type>(std::forward<Observable>(source), trigger_source));
    }
};

}

template<class TriggerObservable>
auto take_until(TriggerObservable&& t)
    ->      detail::take_until_factory<TriggerObservable> {
    return  detail::take_until_factory<TriggerObservable>(std::forward<TriggerObservable>(t));
}

}

}

#endif
<|endoftext|>


<commit_before>#include "processhelper.h"
#include <QtTest>

const char ProcessHelper::Stamp = '%';
bool ProcessHelper::allGreen = true;

ProcessHelper::ProcessHelper(QObject *parent) :
	QObject(parent),
	process(new QProcess(this)),
	exitCode(EXIT_SUCCESS)
{
#if defined(Q_OS_WIN)
	process->setProgram(QStringLiteral(OUTDIR) + QStringLiteral("../../../../examples/backgroundprocess/DemoApp/") + QStringLiteral(RMODE) + QStringLiteral("/DemoApp"));
#elif defined(Q_OS_MAC)
	process->setProgram(QStringLiteral(OUTDIR) + QStringLiteral("../../../../examples/backgroundprocess/DemoApp/DemoApp.app/Contents/MacOS/DemoApp"));
#else
	process->setProgram(QStringLiteral(OUTDIR) + QStringLiteral("../../../../examples/backgroundprocess/DemoApp/DemoApp"));
#endif

	connect(process, &QProcess::errorOccurred,
			this, &ProcessHelper::errorOccurred);
	connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
			this, &ProcessHelper::finished);
}

void ProcessHelper::setExitCode(int code)
{
	exitCode = code;
}

void ProcessHelper::start(const QByteArrayList &commands, bool logpath, int timeout)
{
	QStringList s;
	foreach(auto c, commands)
		s.append(QString::fromUtf8(c));
	if(logpath)
		s.append({QStringLiteral("--logpath"), logPath()});
	process->setArguments(s);
	process->start();
	QVERIFY2(process->waitForStarted(5000), qUtf8Printable(process->errorString()));
	QThread::msleep(timeout);
}

void ProcessHelper::waitForFinished()
{
	if(!process->waitForFinished(5000)) {
		process->terminate();
		QFAIL("Process did not stop by itself");
	}
}

void ProcessHelper::verifyLog(const QByteArrayList &log, bool isError)
{
	allGreen = false;

	if(isError) {
		auto err = process->readAllStandardError();
		QBuffer buffer(&err);
		buffer.open(QIODevice::ReadOnly | QIODevice::Text);
		testLog(log, &buffer);
		buffer.close();
	} else
		testLog(log, process);

	if(!allGreen)
		qDebug() << "on arguments:" << process->arguments();
}

void ProcessHelper::verifyLogEmpty(bool isError)
{
	verifyLog(QByteArrayList(), isError);
}

void ProcessHelper::waitForFinished(const QList<ProcessHelper *> &helpers)
{
	foreach (auto h, helpers)
		h->waitForFinished();
}

void ProcessHelper::clearLog()
{
	auto logFile = logPath();
	if(QFile::exists(logFile))
		QVERIFY(QFile::remove(logFile));
}

void ProcessHelper::verifyMasterLog(const QByteArrayList &log)
{
	auto logFile = logPath();
	QFile file(logFile);
	QVERIFY(file.exists());
	QVERIFY2(file.open(QIODevice::ReadOnly | QIODevice::Text), qUtf8Printable(file.errorString()));

	allGreen = false;
	testLog(log, &file);
	if(!allGreen)
		qDebug() << "on master log";

	file.close();
	QVERIFY(file.remove());

}

void ProcessHelper::errorOccurred(QProcess::ProcessError error)
{
	Q_UNUSED(error)
	QFAIL(qUtf8Printable(process->errorString()));
}

void ProcessHelper::finished(int exitCode, QProcess::ExitStatus exitStatus)
{
	QCOMPARE(exitStatus, QProcess::NormalExit);
	QCOMPARE(exitCode, this->exitCode);
}

QString ProcessHelper::logPath()
{
	return QDir::current().absoluteFilePath(QStringLiteral("MasterTest.log"));
}

void ProcessHelper::testLog(const QByteArrayList &log, QIODevice *device)
{
	auto index = 0;
	while(!device->atEnd()) {
		auto logStr = device->readLine().trimmed();
		if(logStr.isEmpty())
			continue;

		QVERIFY2(index < log.size(), logStr.constData());
		auto testStr = log[index++];

		auto testSplit = testStr.split(Stamp);
		if(testSplit.size() == 2) {
			QVERIFY2(logStr.startsWith(testSplit[0]), logStr.constData());
			QVERIFY2(logStr.endsWith(testSplit[1]), logStr.constData());
		} else
			QCOMPARE(logStr, testStr);
	}
	QCOMPARE(index, log.size());
	allGreen = true;
}
<commit_msg>more debug<commit_after>#include "processhelper.h"
#include <QtTest>

const char ProcessHelper::Stamp = '%';
bool ProcessHelper::allGreen = true;

ProcessHelper::ProcessHelper(QObject *parent) :
	QObject(parent),
	process(new QProcess(this)),
	exitCode(EXIT_SUCCESS)
{
#if defined(Q_OS_WIN)
	process->setProgram(QStringLiteral(OUTDIR) + QStringLiteral("../../../../examples/backgroundprocess/DemoApp/") + QStringLiteral(RMODE) + QStringLiteral("/DemoApp"));
#elif defined(Q_OS_MAC)
	process->setProgram(QStringLiteral(OUTDIR) + QStringLiteral("../../../../examples/backgroundprocess/DemoApp/DemoApp.app/Contents/MacOS/DemoApp"));
#else
	process->setProgram(QStringLiteral(OUTDIR) + QStringLiteral("../../../../examples/backgroundprocess/DemoApp/DemoApp"));
#endif

	connect(process, &QProcess::errorOccurred,
			this, &ProcessHelper::errorOccurred);
	connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
			this, &ProcessHelper::finished);
}

void ProcessHelper::setExitCode(int code)
{
	exitCode = code;
}

void ProcessHelper::start(const QByteArrayList &commands, bool logpath, int timeout)
{
	QStringList s;
	foreach(auto c, commands)
		s.append(QString::fromUtf8(c));
	if(logpath)
		s.append({QStringLiteral("--logpath"), logPath()});
	process->setArguments(s);
	process->start();
	QVERIFY2(process->waitForStarted(5000), qUtf8Printable(process->errorString()));
	QThread::msleep(timeout);
}

void ProcessHelper::waitForFinished()
{
	if(!process->waitForFinished(5000)) {
		process->terminate();
		QFAIL("Process did not stop by itself");
	}
}

void ProcessHelper::verifyLog(const QByteArrayList &log, bool isError)
{
	allGreen = false;

	if(isError) {
		auto err = process->readAllStandardError();
		QBuffer buffer(&err);
		buffer.open(QIODevice::ReadOnly | QIODevice::Text);
		testLog(log, &buffer);
		buffer.close();
	} else
		testLog(log, process);

	if(!allGreen)
		qDebug() << "on arguments:" << process->arguments();
}

void ProcessHelper::verifyLogEmpty(bool isError)
{
	verifyLog(QByteArrayList(), isError);
}

void ProcessHelper::waitForFinished(const QList<ProcessHelper *> &helpers)
{
	foreach (auto h, helpers)
		h->waitForFinished();
}

void ProcessHelper::clearLog()
{
	auto logFile = logPath();
	if(QFile::exists(logFile))
		QVERIFY(QFile::remove(logFile));
}

void ProcessHelper::verifyMasterLog(const QByteArrayList &log)
{
	auto logFile = logPath();
	QFile file(logFile);
	QVERIFY(file.exists());
	qDebug() << file.size();
	QVERIFY2(file.open(QIODevice::ReadOnly | QIODevice::Text), qUtf8Printable(file.errorString()));

	allGreen = false;
	testLog(log, &file);
	if(!allGreen)
		qDebug() << "on master log";

	file.close();
	QVERIFY(file.remove());

}

void ProcessHelper::errorOccurred(QProcess::ProcessError error)
{
	Q_UNUSED(error)
	QFAIL(qUtf8Printable(process->errorString()));
}

void ProcessHelper::finished(int exitCode, QProcess::ExitStatus exitStatus)
{
	QCOMPARE(exitStatus, QProcess::NormalExit);
	QCOMPARE(exitCode, this->exitCode);
}

QString ProcessHelper::logPath()
{
	return QDir::temp().absoluteFilePath(QStringLiteral("MasterTest.log"));
}

void ProcessHelper::testLog(const QByteArrayList &log, QIODevice *device)
{
	auto index = 0;
	while(!device->atEnd()) {
		auto logStr = device->readLine().trimmed();
		qDebug() << logStr;
		if(logStr.isEmpty())
			continue;

		QVERIFY2(index < log.size(), logStr.constData());
		auto testStr = log[index++];

		auto testSplit = testStr.split(Stamp);
		if(testSplit.size() == 2) {
			QVERIFY2(logStr.startsWith(testSplit[0]), logStr.constData());
			QVERIFY2(logStr.endsWith(testSplit[1]), logStr.constData());
		} else
			QCOMPARE(logStr, testStr);
	}
	QCOMPARE(index, log.size());
	allGreen = true;
}
<|endoftext|>


<commit_before>/*
 *  Seek camera interface
 *  Author: Maarten Vandersteegen
 */

#include "SeekCam.h"
#include "SeekLogging.h"

using namespace LibSeek;

SeekCam::SeekCam(int vendor_id, int product_id, uint16_t* buffer, size_t raw_height, size_t raw_width, cv::Rect roi, std::string ffc_filename) :
    m_offset(0x4000),
    m_ffc_filename(ffc_filename),
    m_is_opened(false),
    m_dev(vendor_id, product_id),
    m_raw_data(buffer),
    m_raw_data_size(raw_height * raw_width),
    m_raw_frame(raw_height,
                raw_width,
                CV_16UC1,
                buffer,
                cv::Mat::AUTO_STEP),
    m_flat_field_calibration_frame(),
    m_additional_ffc(),
    m_dead_pixel_mask()
{
    /* set ROI to exclude metadata frame regions */
    m_raw_frame = m_raw_frame(roi);
}

SeekCam::~SeekCam()
{
    close();
}

bool SeekCam::open()
{
    if (m_ffc_filename != std::string()) {
        m_additional_ffc = cv::imread(m_ffc_filename, -1);

        if (m_additional_ffc.type() != m_raw_frame.type()) {
            error("Error: '%s' not found or it has the wrong type: %d\n",
                    m_ffc_filename.c_str(), m_additional_ffc.type());
            return false;
        }

        if (m_additional_ffc.size() != m_raw_frame.size()) {
            error("Error: expected '%s' to have size [%d,%d], got [%d,%d]\n",
                    m_ffc_filename.c_str(),
                    m_raw_frame.cols, m_raw_frame.rows,
                    m_additional_ffc.cols, m_additional_ffc.rows);
            return false;
        }
    }

    return open_cam();
}

void SeekCam::close()
{
    if (m_dev.isOpened()) {
        vector<uint8_t> data = { 0x00, 0x00 };
        m_dev.request_set(DeviceCommand::SET_OPERATION_MODE, data);
        m_dev.request_set(DeviceCommand::SET_OPERATION_MODE, data);
        m_dev.request_set(DeviceCommand::SET_OPERATION_MODE, data);
    }
    m_is_opened = false;
}

bool SeekCam::isOpened()
{
    return m_is_opened;
}

bool SeekCam::grab()
{
    int i;

    for (i=0; i<10; i++) {
        if(!get_frame()) {
            error("Error: frame acquisition failed\n");
            return false;
        }

        if (frame_id() == 3) {
            return true;

        } else if (frame_id() == 1) {
            m_raw_frame.copyTo(m_flat_field_calibration_frame);
        }
    }

    return false;
}

void SeekCam::retrieve(cv::Mat& dst)
{
    /* apply flat field calibration */
    m_raw_frame += m_offset - m_flat_field_calibration_frame;
    /* filter out dead pixels */
    apply_dead_pixel_filter(m_raw_frame, dst);
    /* apply additional flat field calibration for degradient */
    if (!m_additional_ffc.empty())
        dst += m_offset - m_additional_ffc;
}

bool SeekCam::read(cv::Mat& dst)
{
    if (!grab())
        return false;

    retrieve(dst);

    return true;
}

void SeekCam::convertToGreyScale(cv::Mat& src, cv::Mat& dst)
{
    double tmin, tmax, rsize;
    double rnint = 0;
    double rnstart = 0;
    size_t n;
    size_t num_of_pixels = src.rows * src.cols;

    cv::minMaxLoc(src, &tmin, &tmax);
    rsize = (tmax - tmin) / 10.0;

    for (n=0; n<10; n++) {
        double min = tmin + n * rsize;
        cv::Mat mask;
        cv::Mat temp;

        rnstart += rnint;
        cv::inRange(src, cv::Scalar(min), cv::Scalar(min + rsize), mask);
        /* num_of_pixels_in_range / total_num_of_pixels * 256 */
        rnint = (cv::countNonZero(mask) << 8) / num_of_pixels;

        temp = ((src - min) * rnint) / rsize + rnstart;
        temp.copyTo(dst, mask);
    }
    dst.convertTo(dst, CV_8UC1);
}

bool SeekCam::open_cam()
{
    int i;

    if (!m_dev.open()) {
        error("Error: open failed\n");
        return false;
    }

    /* init retry loop: sometimes cam skips first 512 bytes of first frame (needed for dead pixel filter) */
    for (i=0; i<3; i++) {
        /* cam specific configuration */
        if (!init_cam()) {
            error("Error: init_cam failed\n");
            return false;
        }

        if (!get_frame()) {
            error("Error: first frame acquisition failed, retry attempt %d\n", i+1);
            continue;
        }

        if (frame_id() != 4) {
            error("Error: expected first frame to have id 4\n");
            return false;
        }

        m_raw_frame.convertTo(m_dead_pixel_mask, CV_8UC1);
        create_dead_pixel_list();

        if (!grab()) {
            error("Error: first grab failed\n");
            return false;
        }

        m_is_opened = true;
        return true;
    }

    error("Error: max init retry count exceeded\n");
    return false;
}

bool SeekCam::get_frame()
{
    /* request new frame */
    uint8_t* s = reinterpret_cast<uint8_t*>(&m_raw_data_size);

    vector<uint8_t> data = { s[0], s[1], s[2], s[3] };
    if (!m_dev.request_set(DeviceCommand::START_GET_IMAGE_TRANSFER, data))
        return false;

    /* store frame data */
    if (!m_dev.fetch_frame(m_raw_data, m_raw_data_size))
        return false;

    return true;
}

void SeekCam::print_usb_data(vector<uint8_t>& data)
{
    debug("Response: ");
    for (size_t i = 0; i < data.size(); i++) {
        debug(" %2x", data[i]);
    }
    debug("\n");
}

void SeekCam::create_dead_pixel_list()
{
    int x, y;
    m_dead_pixel_list.clear();

    for (y=0; y<m_dead_pixel_mask.rows; y++) {
        for (x=0; x<m_dead_pixel_mask.cols; x++) {
            if (m_dead_pixel_mask.at<uint8_t>(y, x) == 0) {
                m_dead_pixel_list.push_back(cv::Point(x, y));
            }
        }
    }
}

void SeekCam::apply_dead_pixel_filter(cv::Mat& src, cv::Mat& dst)
{
    size_t i;
    size_t size = m_dead_pixel_list.size();
    int right_border = src.cols - 1;
    int lower_border = src.rows - 1;

    dst.create(src.rows, src.cols, src.type()); /* ensure dst is properly allocated */
    dst.setTo(0xffff);                          /* value to identify dead pixels */
    src.copyTo(dst, m_dead_pixel_mask);         /* only copy non dead pixel values */

    /* replace dead pixel values (0xffff) with the mean of its non dead surrounding pixels */
    for (i=0; i<size; i++) {
        cv::Point p = m_dead_pixel_list[i];
        dst.at<uint16_t>(p) = calc_mean_value(dst, p, right_border, lower_border);
    }
}

uint16_t SeekCam::calc_mean_value(cv::Mat& img, cv::Point p, int right_border, int lower_border)
{
    uint32_t value = 0, temp;
    uint32_t div = 0;

    if (p.x != 0) {
        /* if not on the left border of the image */
        temp = img.at<uint16_t>(p.y, p.x-1);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }
    if (p.x != right_border) {
        /* if not on the right border of the image */
        temp = img.at<uint16_t>(p.y, p.x+1);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }
    if (p.y != 0) {
        // upper
        temp = img.at<uint16_t>(p.y-1, p.x);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }
    if (p.y != lower_border) {
        // lower
        temp = img.at<uint16_t>(p.y+1, p.x);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }

    if (div)
        return (value / div);

    return 0;
}
<commit_msg>Code instrumentation to get flat field frame, dead pixel frame and one data frame<commit_after>/*
 *  Seek camera interface
 *  Author: Maarten Vandersteegen
 */

#include "SeekCam.h"
#include "SeekLogging.h"

using namespace LibSeek;

SeekCam::SeekCam(int vendor_id, int product_id, uint16_t* buffer, size_t raw_height, size_t raw_width, cv::Rect roi, std::string ffc_filename) :
    m_offset(0x4000),
    m_ffc_filename(ffc_filename),
    m_is_opened(false),
    m_dev(vendor_id, product_id),
    m_raw_data(buffer),
    m_raw_data_size(raw_height * raw_width),
    m_raw_frame(raw_height,
                raw_width,
                CV_16UC1,
                buffer,
                cv::Mat::AUTO_STEP),
    m_flat_field_calibration_frame(),
    m_additional_ffc(),
    m_dead_pixel_mask()
{
    /* set ROI to exclude metadata frame regions */
    m_raw_frame = m_raw_frame(roi);
}

SeekCam::~SeekCam()
{
    close();
}

bool SeekCam::open()
{
    if (m_ffc_filename != std::string()) {
        m_additional_ffc = cv::imread(m_ffc_filename, -1);

        if (m_additional_ffc.type() != m_raw_frame.type()) {
            error("Error: '%s' not found or it has the wrong type: %d\n",
                    m_ffc_filename.c_str(), m_additional_ffc.type());
            return false;
        }

        if (m_additional_ffc.size() != m_raw_frame.size()) {
            error("Error: expected '%s' to have size [%d,%d], got [%d,%d]\n",
                    m_ffc_filename.c_str(),
                    m_raw_frame.cols, m_raw_frame.rows,
                    m_additional_ffc.cols, m_additional_ffc.rows);
            return false;
        }
    }

    return open_cam();
}

void SeekCam::close()
{
    if (m_dev.isOpened()) {
        vector<uint8_t> data = { 0x00, 0x00 };
        m_dev.request_set(DeviceCommand::SET_OPERATION_MODE, data);
        m_dev.request_set(DeviceCommand::SET_OPERATION_MODE, data);
        m_dev.request_set(DeviceCommand::SET_OPERATION_MODE, data);
    }
    m_is_opened = false;
}

bool SeekCam::isOpened()
{
    return m_is_opened;
}

bool SeekCam::grab()
{
    int i;

    for (i=0; i<10; i++) {
        if(!get_frame()) {
            error("Error: frame acquisition failed\n");
            return false;
        }

        if (frame_id() == 3) {
            cv::imwrite("frame_id_3.png", m_raw_frame);
            exit(0);
            return true;

        } else if (frame_id() == 1) {
            cv::imwrite("frame_id_1.png", m_raw_frame);
            m_raw_frame.copyTo(m_flat_field_calibration_frame);
        }
    }

    return false;
}

void SeekCam::retrieve(cv::Mat& dst)
{
    /* apply flat field calibration */
    m_raw_frame += m_offset - m_flat_field_calibration_frame;
    /* filter out dead pixels */
    apply_dead_pixel_filter(m_raw_frame, dst);
    /* apply additional flat field calibration for degradient */
    if (!m_additional_ffc.empty())
        dst += m_offset - m_additional_ffc;
}

bool SeekCam::read(cv::Mat& dst)
{
    if (!grab())
        return false;

    retrieve(dst);

    return true;
}

void SeekCam::convertToGreyScale(cv::Mat& src, cv::Mat& dst)
{
    double tmin, tmax, rsize;
    double rnint = 0;
    double rnstart = 0;
    size_t n;
    size_t num_of_pixels = src.rows * src.cols;

    cv::minMaxLoc(src, &tmin, &tmax);
    rsize = (tmax - tmin) / 10.0;

    for (n=0; n<10; n++) {
        double min = tmin + n * rsize;
        cv::Mat mask;
        cv::Mat temp;

        rnstart += rnint;
        cv::inRange(src, cv::Scalar(min), cv::Scalar(min + rsize), mask);
        /* num_of_pixels_in_range / total_num_of_pixels * 256 */
        rnint = (cv::countNonZero(mask) << 8) / num_of_pixels;

        temp = ((src - min) * rnint) / rsize + rnstart;
        temp.copyTo(dst, mask);
    }
    dst.convertTo(dst, CV_8UC1);
}

bool SeekCam::open_cam()
{
    int i;

    if (!m_dev.open()) {
        error("Error: open failed\n");
        return false;
    }

    /* init retry loop: sometimes cam skips first 512 bytes of first frame (needed for dead pixel filter) */
    for (i=0; i<3; i++) {
        /* cam specific configuration */
        if (!init_cam()) {
            error("Error: init_cam failed\n");
            return false;
        }

        if (!get_frame()) {
            error("Error: first frame acquisition failed, retry attempt %d\n", i+1);
            continue;
        }

        if (frame_id() != 4) {
            error("Error: expected first frame to have id 4\n");
            return false;
        }

        cv::imwrite("frame_id_4.png", m_raw_frame);
        m_raw_frame.convertTo(m_dead_pixel_mask, CV_8UC1);
        create_dead_pixel_list();

        if (!grab()) {
            error("Error: first grab failed\n");
            return false;
        }

        m_is_opened = true;
        return true;
    }

    error("Error: max init retry count exceeded\n");
    return false;
}

bool SeekCam::get_frame()
{
    /* request new frame */
    uint8_t* s = reinterpret_cast<uint8_t*>(&m_raw_data_size);

    vector<uint8_t> data = { s[0], s[1], s[2], s[3] };
    if (!m_dev.request_set(DeviceCommand::START_GET_IMAGE_TRANSFER, data))
        return false;

    /* store frame data */
    if (!m_dev.fetch_frame(m_raw_data, m_raw_data_size))
        return false;

    return true;
}

void SeekCam::print_usb_data(vector<uint8_t>& data)
{
    debug("Response: ");
    for (size_t i = 0; i < data.size(); i++) {
        debug(" %2x", data[i]);
    }
    debug("\n");
}

void SeekCam::create_dead_pixel_list()
{
    int x, y;
    m_dead_pixel_list.clear();

    for (y=0; y<m_dead_pixel_mask.rows; y++) {
        for (x=0; x<m_dead_pixel_mask.cols; x++) {
            if (m_dead_pixel_mask.at<uint8_t>(y, x) == 0) {
                m_dead_pixel_list.push_back(cv::Point(x, y));
            }
        }
    }
}

void SeekCam::apply_dead_pixel_filter(cv::Mat& src, cv::Mat& dst)
{
    size_t i;
    size_t size = m_dead_pixel_list.size();
    int right_border = src.cols - 1;
    int lower_border = src.rows - 1;

    dst.create(src.rows, src.cols, src.type()); /* ensure dst is properly allocated */
    dst.setTo(0xffff);                          /* value to identify dead pixels */
    src.copyTo(dst, m_dead_pixel_mask);         /* only copy non dead pixel values */

    /* replace dead pixel values (0xffff) with the mean of its non dead surrounding pixels */
    for (i=0; i<size; i++) {
        cv::Point p = m_dead_pixel_list[i];
        dst.at<uint16_t>(p) = calc_mean_value(dst, p, right_border, lower_border);
    }
}

uint16_t SeekCam::calc_mean_value(cv::Mat& img, cv::Point p, int right_border, int lower_border)
{
    uint32_t value = 0, temp;
    uint32_t div = 0;

    if (p.x != 0) {
        /* if not on the left border of the image */
        temp = img.at<uint16_t>(p.y, p.x-1);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }
    if (p.x != right_border) {
        /* if not on the right border of the image */
        temp = img.at<uint16_t>(p.y, p.x+1);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }
    if (p.y != 0) {
        // upper
        temp = img.at<uint16_t>(p.y-1, p.x);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }
    if (p.y != lower_border) {
        // lower
        temp = img.at<uint16_t>(p.y+1, p.x);
        if (temp != 0xffff) {
            value += temp;
            div++;
        }
    }

    if (div)
        return (value / div);

    return 0;
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *	  notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in
 *	  the documentation and/or other materials provided with the
 *	  distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *	  if any, must include the following acknowledgment:
 *		 "This product includes software developed by the
 *		  Apache Software Foundation (http://www.apache.org/)."
 *	  Alternately, this acknowledgment may appear in the software itself,
 *	  if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *	  not be used to endorse or promote products derived from this
 *	  software without prior written permission. For written
 *	  permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *	  nor may "Apache" appear in their name, without prior written
 *	  permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#if defined XALAN_NLS_MSG_LOADER

// Class header file.
#include "XalanNLSMessageLoader.hpp"

#include <xercesc/util/XMLMsgLoader.hpp>

#include <xalanc/PlatformSupport/DOMStringHelper.hpp>

#include <string.h>

#include <errno.h>

XALAN_CPP_NAMESPACE_BEGIN

XALAN_USING_XERCES(XMLMsgLoader)

static const char* const	MSG_FILE_NAME = "XalanMsg_";

#define MAX_LOCALTION_NAME 1024

static const char* const	s_errorMessage = "Message can't be located in the NLS catalog.";

XalanNLSMessageLoader::~XalanNLSMessageLoader()
{
	if ((int)m_catalogHandle != -1)
	{
		catclose(m_catalogHandle);
	}
}

XalanNLSMessageLoader::XalanNLSMessageLoader() :
	m_catalogHandle(nl_catd(-1))
{

    char fileName[50];
    fileName[0] = 0;

    sprintf(fileName,"%s", MSG_FILE_NAME);

	const char* Locale = XMLMsgLoader::getLocale();

    if(Locale == 0)
    {
   		Locale = "en_US";
    }

	strcat(fileName, Locale);

    strcat(fileName, ".cat");

   /**
    * To open user-specified locale specific cat file
    * and default cat file if necessary
    */
    m_catalogHandle = catopen(fileName, 0);

    if ((int)m_catalogHandle == -1)
    {
        // Probably have to call panic here
        // the user will get an error with retrieving messages
 		assert(0);
    }
}

bool XalanNLSMessageLoader::loadMsg(XalanMessages::Codes    msgToLoad
								, XalanDOMChar*		toFill
								, unsigned int            maxChars)
{

    bool bRetValue = false;

    if( toFill == 0 || maxChars == 0 )
    {
    	return bRetValue;
    }

    if ((int)m_catalogHandle) == -1)
    {
    	// for transcoding to Unicode
    	const XalanDOMString	errorMsg("Message can't be retrieved: the message catalog is not open.");

    	if(errorMsg.length() < maxChars)
    	{
    		XalanCopy(errorMsg.c_str(), errorMsg.c_str()+ errorMsg.length() +1 , toFill);
    	}
    }
    else
    {
    	const char* const	catMessage = catgets( m_catalogHandle, 1, (int)msgToLoad+2, s_errorMessage);

		// catgets returns a pointer to msgString if it fails to locate the message
		// from the message catalog
    	if (catMessage != 0)
    	{
        	const XalanDOMString	errorMsg(catMessage);

        	if(errorMsg.length() < maxChars)
    		{
    			XalanCopy(errorMsg.c_str(), errorMsg.c_str() + errorMsg.length() +1  , toFill);

    			bRetValue = true;
    		}
        }
    }

    return bRetValue;
}

XALAN_CPP_NAMESPACE_END

#endif // XALAN_NLS_MSG_LOADER

<commit_msg>Fixed code glitch.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *	  notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in
 *	  the documentation and/or other materials provided with the
 *	  distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *	  if any, must include the following acknowledgment:
 *		 "This product includes software developed by the
 *		  Apache Software Foundation (http://www.apache.org/)."
 *	  Alternately, this acknowledgment may appear in the software itself,
 *	  if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *	  not be used to endorse or promote products derived from this
 *	  software without prior written permission. For written
 *	  permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *	  nor may "Apache" appear in their name, without prior written
 *	  permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#if defined XALAN_NLS_MSG_LOADER

// Class header file.
#include "XalanNLSMessageLoader.hpp"

#include <xercesc/util/XMLMsgLoader.hpp>

#include <xalanc/PlatformSupport/DOMStringHelper.hpp>

#include <string.h>

#include <errno.h>

XALAN_CPP_NAMESPACE_BEGIN

XALAN_USING_XERCES(XMLMsgLoader)

static const char* const	MSG_FILE_NAME = "XalanMsg_";

#define MAX_LOCALTION_NAME 1024

static const char* const	s_errorMessage = "Message can't be located in the NLS catalog.";

XalanNLSMessageLoader::~XalanNLSMessageLoader()
{
	if ((int)m_catalogHandle != -1)
	{
		catclose(m_catalogHandle);
	}
}

XalanNLSMessageLoader::XalanNLSMessageLoader() :
	m_catalogHandle(nl_catd(-1))
{

    char fileName[50];
    fileName[0] = 0;

    sprintf(fileName,"%s", MSG_FILE_NAME);

	const char* Locale = XMLMsgLoader::getLocale();

    if(Locale == 0)
    {
   		Locale = "en_US";
    }

	strcat(fileName, Locale);

    strcat(fileName, ".cat");

   /**
    * To open user-specified locale specific cat file
    * and default cat file if necessary
    */
    m_catalogHandle = catopen(fileName, 0);

    if ((int)m_catalogHandle == -1)
    {
        // Probably have to call panic here
        // the user will get an error with retrieving messages
 		assert(0);
    }
}

bool XalanNLSMessageLoader::loadMsg(XalanMessages::Codes    msgToLoad
								, XalanDOMChar*		toFill
								, unsigned int            maxChars)
{

    bool bRetValue = false;

    if( toFill == 0 || maxChars == 0 )
    {
    	return bRetValue;
    }

    if ((int)m_catalogHandle == -1)
    {
    	// for transcoding to Unicode
    	const XalanDOMString	errorMsg("Message can't be retrieved: the message catalog is not open.");

    	if(errorMsg.length() < maxChars)
    	{
    		XalanCopy(errorMsg.c_str(), errorMsg.c_str()+ errorMsg.length() +1 , toFill);
    	}
    }
    else
    {
    	const char* const	catMessage = catgets( m_catalogHandle, 1, (int)msgToLoad+2, s_errorMessage);

		// catgets returns a pointer to msgString if it fails to locate the message
		// from the message catalog
    	if (catMessage != 0)
    	{
        	const XalanDOMString	errorMsg(catMessage);

        	if(errorMsg.length() < maxChars)
    		{
    			XalanCopy(errorMsg.c_str(), errorMsg.c_str() + errorMsg.length() +1  , toFill);

    			bRetValue = true;
    		}
        }
    }

    return bRetValue;
}

XALAN_CPP_NAMESPACE_END

#endif // XALAN_NLS_MSG_LOADER

<|endoftext|>


<commit_before>// $Id: uniform_refinement_estimator.C,v 1.1 2006-06-12 19:25:38 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <algorithm> // for std::fill
#include <cmath>    // for sqrt

// Local Includes
#include "libmesh_common.h"
#include "uniform_refinement_estimator.h"
#include "dof_map.h"
#include "fe.h"
#include "fe_interface.h"
#include "quadrature.h"
#include "libmesh_logging.h"
#include "elem.h"
#include "mesh.h"
#include "mesh_refinement.h"
#include "numeric_vector.h"
#include "system.h"

//-----------------------------------------------------------------
// ErrorEstimator implementations
void UniformRefinementEstimator::estimate_error (const System& _system,
					  std::vector<float>& error_per_cell)
{
  // We have to break the rules here, because we can't refine a const System
  System& system = const_cast<System &>(_system);

  // The current mesh
  Mesh& mesh = system.get_mesh();

  // The dimensionality of the mesh
  const unsigned int dim = mesh.mesh_dimension();

  // The number of variables in the system
  const unsigned int n_vars = system.n_vars();

  // The DofMap for this system
  const DofMap& dof_map = system.get_dof_map();

  // Resize the error_per_cell vector to be
  // the number of elements, initialize it to 0.
  error_per_cell.resize (mesh.n_elem());
  std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);

  // Check for a valid component_scale
  if (!component_scale.empty())
    {
      if (component_scale.size() != n_vars)
	{
	  std::cerr << "ERROR: component_scale is the wrong size:"
		    << std::endl
		    << " component_scale.scale()=" << component_scale.size()
		    << std::endl
		    << " n_vars=" << n_vars
		    << std::endl;
	  error();
	}
    }
  else
    {
      // No specified scaling.  Scale all variables by one.
      component_scale.resize (n_vars);
      std::fill (component_scale.begin(), component_scale.end(), 1.0);
    }

  // Back up the coarse grid vectors
  std::map<std::string, NumericVector<Number> *> coarse_vectors;
  for (System::vectors_iterator vec = system.vectors_begin(); vec !=
       system.vectors_end(); ++vec)
    {
      // The (string) name of this vector
      const std::string& var_name = vec->first;

      coarse_vectors[var_name] = vec->second->clone().get();
    }

  // Find the number of coarse mesh elements, to make it possible
  // to find correct coarse elem ids later
  const unsigned int n_coarse_elem = mesh.n_elem();

  // Uniformly refine the mesh, making sure the solution is projected
  bool old_projection_setting = system.project_solution_on_reinit();
  system.project_solution_on_reinit() = true;

  MeshRefinement mesh_refinement(mesh);

  assert (number_h_refinements > 0 || number_p_refinements > 0);

  for (unsigned int i = 0; i != number_h_refinements; ++i)
    {
      mesh_refinement.uniformly_refine(1);
      system.reinit();
    }

  for (unsigned int i = 0; i != number_p_refinements; ++i)
    {
      mesh_refinement.uniformly_p_refine(1);
      system.reinit();
    }

  system.project_solution_on_reinit() = old_projection_setting;

  // Copy the projected coarse grid solution, which will be
  // overwritten by solve()
  AutoPtr<NumericVector<Number> > projected_solution = system.solution->clone();

  // Get the uniformly refined solution.
  // FIXME: this will break if there is more than one System
  // on this mesh and our system relies on data from the others

  system.solve();

  // Get the error in the uniformly refined solution.

  // Loop over all the variables in the system
  for (unsigned int var=0; var<n_vars; var++)
    {
      // Possibly skip this variable
      if (!component_scale.empty())
	if (component_scale[var] == 0.0) continue;

      // The type of finite element to use for this variable
      const FEType& fe_type = dof_map.variable_type (var);

      // Finite element object for each fine element
      AutoPtr<FEBase> fe (FEBase::build (dim, fe_type));

      // Build and attach an appropriate quadrature rule
      AutoPtr<QBase> qrule = fe_type.default_quadrature_rule(dim);
      fe->attach_quadrature_rule (qrule.get());

      const std::vector<Real>&  JxW = fe->get_JxW();
      const std::vector<std::vector<Real> >& phi = fe->get_phi();
      const std::vector<std::vector<RealGradient> >& dphi =
        fe->get_dphi();
#ifdef ENABLE_SECOND_DERIVATIVES
      const std::vector<std::vector<RealTensor> >& d2phi =
        fe->get_d2phi();
#endif

      // The global DOF indices for the fine element
      std::vector<unsigned int> dof_indices;

      // Iterate over all the active elements in the fine mesh
      // that live on this processor.
      MeshBase::const_element_iterator       elem_it  = mesh.active_local_elements_begin();
      const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end();

      for (; elem_it != elem_end; ++elem_it)
	{
	  // e is necessarily an active element on the local processor
	  const Elem* elem = *elem_it;

          // Find the element id for the corresponding coarse grid element
          const Elem* coarse = elem;
          unsigned int e_id = coarse->id();
          while (e_id >= n_coarse_elem)
            {
              assert (coarse->parent());
              coarse = coarse->parent();
              e_id = coarse->id();
            }

          double L2normsq = 0., H1seminormsq = 0., H2seminormsq = 0.;

          // reinitialize the element-specific data
          // for the current element
          fe->reinit (elem);

          // Get the local to global degree of freedom maps
          dof_map.dof_indices (elem, dof_indices, var);

          // The number of quadrature points
          const unsigned int n_qp = qrule->n_points();

          // The number of shape functions
          const unsigned int n_sf = dof_indices.size();

          //
          // Begin the loop over the Quadrature points.
          //
          for (unsigned int qp=0; qp<n_qp; qp++)
            {
              Number u_fine = 0., u_coarse = 0.;

#ifndef USE_COMPLEX_NUMBERS
              RealGradient grad_u_fine, grad_u_coarse;
#else
              // Gradient     grad_u_fine;
              RealGradient grad_u_fine_re, grad_u_coarse_re;
              RealGradient grad_u_fine_im, grad_u_coarse_im;
#endif
#ifdef ENABLE_SECOND_DERIVATIVES
  #ifndef USE_COMPLEX_NUMBERS
              RealTensor grad2_u_fine, grad2_u_coarse;
  #else
              RealTensor grad2_u_fine_re, grad2_u_coarse_re;
              RealTensor grad2_u_fine_im, grad2_u_coarse_im;
  #endif
#endif

              // Compute solution values at the current
              // quadrature point.  This reqiures a sum
              // over all the shape functions evaluated
              // at the quadrature point.
              for (unsigned int i=0; i<n_sf; i++)
                {
                  u_fine            += phi[i][qp]*system.current_solution (dof_indices[i]);
                  u_coarse          += phi[i][qp]*(*projected_solution) (dof_indices[i]);
#ifndef USE_COMPLEX_NUMBERS
                  grad_u_fine       += dphi[i][qp]*system.current_solution (dof_indices[i]);
                  grad_u_coarse     += dphi[i][qp]*(*projected_solution) (dof_indices[i]);
#else
                  grad_u_fine_re    += dphi[i][qp]*system.current_solution (dof_indices[i]).real();
                  grad_u_fine_im    += dphi[i][qp]*system.current_solution (dof_indices[i]).imag();
                  grad_u_coarse_re  += dphi[i][qp]*(*projected_solution) (dof_indices[i]).real();
                  grad_u_coarse_im  += dphi[i][qp]*(*projected_solution) (dof_indices[i]).imag();
#endif
#ifdef ENABLE_SECOND_DERIVATIVES
  #ifndef USE_COMPLEX_NUMBERS
                  grad2_u_fine      += d2phi[i][qp]*system.current_solution (dof_indices[i]);
                  grad2_u_coarse    += d2phi[i][qp]*(*projected_solution) (dof_indices[i]);
  #else
                  grad2_u_fine_re   += d2phi[i][qp]*system.current_solution (dof_indices[i]).real();
                  grad2_u_fine_im   += d2phi[i][qp]*system.current_solution (dof_indices[i]).imag();
                  grad2_u_coarse_re += d2phi[i][qp]*(*projected_solution) (dof_indices[i]).real();
                  grad2_u_coarse_im += d2phi[i][qp]*(*projected_solution) (dof_indices[i]).imag();
  #endif
#endif
                }

#ifdef USE_COMPLEX_NUMBERS
              Gradient grad_u_fine (grad_u_fine_re, grad_u_fine_im);
  #ifdef ENABLE_SECOND_DERIVATIVES
              Tensor grad2_u_fine (grad2_u_fine_re, grad2_u_fine_im);
  #endif
#endif

              // Compute the value of the error at this quadrature point
              const Number val_error = u_fine - u_coarse;

              // Add the squares of the error to each contribution
#ifndef USE_COMPLEX_NUMBERS
              L2normsq += JxW[qp]*(val_error*val_error);
#else
              L2normsq += JxW[qp]*std::norm(val_error);
#endif

              // Compute the value of the error in the gradient at this
              // quadrature point
              if (_sobolev_order > 0)
                {
                  Gradient grad_error = grad_u_fine - grad_u_coarse;

#ifndef USE_COMPLEX_NUMBERS
                  H1seminormsq += JxW[qp]*(grad_error*grad_error);
#else
                  H1seminormsq += JxW[qp]*std::abs(grad_error*grad_error);
#endif
                }

#ifdef ENABLE_SECOND_DERIVATIVES
              // Compute the value of the error in the hessian at this
              // quadrature point
              if (_sobolev_order > 1)
                {
                  Tensor grad2_error = grad2_u_fine - grad2_u_coarse;

                  H2seminormsq += JxW[qp]*(grad2_error.contract(grad2_error));
                }
#endif

            } // end qp loop

          assert (L2normsq     >= 0.);
          assert (H1seminormsq >= 0.);

          error_per_cell[e_id] = L2normsq;
          if (_sobolev_order > 0)
            error_per_cell[e_id] += H1seminormsq;
          if (_sobolev_order > 1)
            error_per_cell[e_id] += H2seminormsq;

        } // End loop over active local elements
    } // End loop over variables

  // Each processor has now computed the error contribuions
  // for its local elements.  We need to sum the vector
  // and then take the square-root of each component.  Note
  // that we only need to sum if we are running on multiple
  // processors, and we only need to take the square-root
  // if the value is nonzero.  There will in general be many
  // zeros for the inactive elements.

  // First sum the vector of estimated error values
  this->reduce_error(error_per_cell);

  // Compute the square-root of each component.
  START_LOG("std::sqrt()", "UniformRefinementEstimator");
  for (unsigned int i=0; i<error_per_cell.size(); i++)
    if (error_per_cell[i] != 0.)
      error_per_cell[i] = std::sqrt(error_per_cell[i]);
  STOP_LOG("std::sqrt()", "UniformRefinementEstimator");

  // Restore the coarse solution vectors and delete their copies
  for (System::vectors_iterator vec = system.vectors_begin(); vec !=
       system.vectors_end(); ++vec)
    {
      // The (string) name of this vector
      const std::string& var_name = vec->first;

      system.get_vector(var_name) = *coarse_vectors[var_name];

      coarse_vectors[var_name]->clear();
      delete coarse_vectors[var_name];
    }
}
<commit_msg>Bugfixes - UniformRefinementEstimator seems to work now<commit_after>// $Id: uniform_refinement_estimator.C,v 1.2 2006-06-12 21:51:14 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <algorithm> // for std::fill
#include <cmath>    // for sqrt

// Local Includes
#include "dof_map.h"
#include "elem.h"
#include "equation_systems.h"
#include "fe.h"
#include "fe_interface.h"
#include "libmesh_common.h"
#include "libmesh_logging.h"
#include "mesh.h"
#include "mesh_refinement.h"
#include "numeric_vector.h"
#include "quadrature.h"
#include "system.h"
#include "uniform_refinement_estimator.h"

//-----------------------------------------------------------------
// ErrorEstimator implementations
void UniformRefinementEstimator::estimate_error (const System& _system,
					  std::vector<float>& error_per_cell)
{
  START_LOG("estimate_error()", "UniformRefinementEstimator");

  // We have to break the rules here, because we can't refine a const System
  System& system = const_cast<System &>(_system);

  // The current mesh
  Mesh& mesh = system.get_mesh();

  // The dimensionality of the mesh
  const unsigned int dim = mesh.mesh_dimension();

  // The number of variables in the system
  const unsigned int n_vars = system.n_vars();

  // The DofMap for this system
  const DofMap& dof_map = system.get_dof_map();

  // Resize the error_per_cell vector to be
  // the number of elements, initialize it to 0.
  error_per_cell.resize (mesh.n_elem());
  std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);

  // Check for a valid component_scale
  if (!component_scale.empty())
    {
      if (component_scale.size() != n_vars)
	{
	  std::cerr << "ERROR: component_scale is the wrong size:"
		    << std::endl
		    << " component_scale.scale()=" << component_scale.size()
		    << std::endl
		    << " n_vars=" << n_vars
		    << std::endl;
	  error();
	}
    }
  else
    {
      // No specified scaling.  Scale all variables by one.
      component_scale.resize (n_vars);
      std::fill (component_scale.begin(), component_scale.end(), 1.0);
    }

  NumericVector<Number> * debugging;

  // Back up the coarse grid vectors
  std::map<std::string, NumericVector<Number> *> coarse_vectors;
  for (System::vectors_iterator vec = system.vectors_begin(); vec !=
       system.vectors_end(); ++vec)
    {
      // The (string) name of this vector
      const std::string& var_name = vec->first;

      coarse_vectors[var_name] = vec->second->clone().release();
      debugging = coarse_vectors[var_name];
    }

  // Find the number of coarse mesh elements, to make it possible
  // to find correct coarse elem ids later
  const unsigned int n_coarse_elem = mesh.n_elem();

  // Uniformly refine the mesh, making sure the solution is projected
  bool old_projection_setting = system.project_solution_on_reinit();
  system.project_solution_on_reinit() = true;

  MeshRefinement mesh_refinement(mesh);

  assert (number_h_refinements > 0 || number_p_refinements > 0);

  // FIXME: this will probably break if there is more than one System
  // on this mesh
  for (unsigned int i = 0; i != number_h_refinements; ++i)
    {
      mesh_refinement.uniformly_refine(1);
      system.get_equation_systems().reinit();
    }

  for (unsigned int i = 0; i != number_p_refinements; ++i)
    {
      mesh_refinement.uniformly_p_refine(1);
      system.get_equation_systems().reinit();
    }

  system.project_solution_on_reinit() = old_projection_setting;

  // Copy the projected coarse grid solution, which will be
  // overwritten by solve()
  AutoPtr<NumericVector<Number> > projected_solution = system.solution->clone();

  // Get the uniformly refined solution.

  system.solve();

  // Get the error in the uniformly refined solution.

  // Loop over all the variables in the system
  for (unsigned int var=0; var<n_vars; var++)
    {
      // Possibly skip this variable
      if (!component_scale.empty())
	if (component_scale[var] == 0.0) continue;

      // The type of finite element to use for this variable
      const FEType& fe_type = dof_map.variable_type (var);

      // Finite element object for each fine element
      AutoPtr<FEBase> fe (FEBase::build (dim, fe_type));

      // Build and attach an appropriate quadrature rule
      AutoPtr<QBase> qrule = fe_type.default_quadrature_rule(dim);
      fe->attach_quadrature_rule (qrule.get());

      const std::vector<Real>&  JxW = fe->get_JxW();
      const std::vector<std::vector<Real> >& phi = fe->get_phi();
      const std::vector<std::vector<RealGradient> >& dphi =
        fe->get_dphi();
#ifdef ENABLE_SECOND_DERIVATIVES
      const std::vector<std::vector<RealTensor> >& d2phi =
        fe->get_d2phi();
#endif

      // The global DOF indices for the fine element
      std::vector<unsigned int> dof_indices;

      // Iterate over all the active elements in the fine mesh
      // that live on this processor.
      MeshBase::const_element_iterator       elem_it  = mesh.active_local_elements_begin();
      const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end();

      for (; elem_it != elem_end; ++elem_it)
	{
	  // e is necessarily an active element on the local processor
	  const Elem* elem = *elem_it;

          // Find the element id for the corresponding coarse grid element
          const Elem* coarse = elem;
          unsigned int e_id = coarse->id();
          while (e_id >= n_coarse_elem)
            {
              assert (coarse->parent());
              coarse = coarse->parent();
              e_id = coarse->id();
            }

          double L2normsq = 0., H1seminormsq = 0., H2seminormsq = 0.;

          // reinitialize the element-specific data
          // for the current element
          fe->reinit (elem);

          // Get the local to global degree of freedom maps
          dof_map.dof_indices (elem, dof_indices, var);

          // The number of quadrature points
          const unsigned int n_qp = qrule->n_points();

          // The number of shape functions
          const unsigned int n_sf = dof_indices.size();

          //
          // Begin the loop over the Quadrature points.
          //
          for (unsigned int qp=0; qp<n_qp; qp++)
            {
              Number u_fine = 0., u_coarse = 0.;

#ifndef USE_COMPLEX_NUMBERS
              RealGradient grad_u_fine, grad_u_coarse;
#else
              // Gradient     grad_u_fine;
              RealGradient grad_u_fine_re, grad_u_coarse_re;
              RealGradient grad_u_fine_im, grad_u_coarse_im;
#endif
#ifdef ENABLE_SECOND_DERIVATIVES
  #ifndef USE_COMPLEX_NUMBERS
              RealTensor grad2_u_fine, grad2_u_coarse;
  #else
              RealTensor grad2_u_fine_re, grad2_u_coarse_re;
              RealTensor grad2_u_fine_im, grad2_u_coarse_im;
  #endif
#endif

              // Compute solution values at the current
              // quadrature point.  This reqiures a sum
              // over all the shape functions evaluated
              // at the quadrature point.
              for (unsigned int i=0; i<n_sf; i++)
                {
                  u_fine            += phi[i][qp]*system.current_solution (dof_indices[i]);
                  u_coarse          += phi[i][qp]*(*projected_solution) (dof_indices[i]);
#ifndef USE_COMPLEX_NUMBERS
                  grad_u_fine       += dphi[i][qp]*system.current_solution (dof_indices[i]);
                  grad_u_coarse     += dphi[i][qp]*(*projected_solution) (dof_indices[i]);
#else
                  grad_u_fine_re    += dphi[i][qp]*system.current_solution (dof_indices[i]).real();
                  grad_u_fine_im    += dphi[i][qp]*system.current_solution (dof_indices[i]).imag();
                  grad_u_coarse_re  += dphi[i][qp]*(*projected_solution) (dof_indices[i]).real();
                  grad_u_coarse_im  += dphi[i][qp]*(*projected_solution) (dof_indices[i]).imag();
#endif
#ifdef ENABLE_SECOND_DERIVATIVES
  #ifndef USE_COMPLEX_NUMBERS
                  grad2_u_fine      += d2phi[i][qp]*system.current_solution (dof_indices[i]);
                  grad2_u_coarse    += d2phi[i][qp]*(*projected_solution) (dof_indices[i]);
  #else
                  grad2_u_fine_re   += d2phi[i][qp]*system.current_solution (dof_indices[i]).real();
                  grad2_u_fine_im   += d2phi[i][qp]*system.current_solution (dof_indices[i]).imag();
                  grad2_u_coarse_re += d2phi[i][qp]*(*projected_solution) (dof_indices[i]).real();
                  grad2_u_coarse_im += d2phi[i][qp]*(*projected_solution) (dof_indices[i]).imag();
  #endif
#endif
                }

#ifdef USE_COMPLEX_NUMBERS
              Gradient grad_u_fine (grad_u_fine_re, grad_u_fine_im);
  #ifdef ENABLE_SECOND_DERIVATIVES
              Tensor grad2_u_fine (grad2_u_fine_re, grad2_u_fine_im);
  #endif
#endif

              // Compute the value of the error at this quadrature point
              const Number val_error = u_fine - u_coarse;

              // Add the squares of the error to each contribution
#ifndef USE_COMPLEX_NUMBERS
              L2normsq += JxW[qp]*(val_error*val_error);
#else
              L2normsq += JxW[qp]*std::norm(val_error);
#endif

              // Compute the value of the error in the gradient at this
              // quadrature point
              if (_sobolev_order > 0)
                {
                  Gradient grad_error = grad_u_fine - grad_u_coarse;

#ifndef USE_COMPLEX_NUMBERS
                  H1seminormsq += JxW[qp]*(grad_error*grad_error);
#else
                  H1seminormsq += JxW[qp]*std::abs(grad_error*grad_error);
#endif
                }

#ifdef ENABLE_SECOND_DERIVATIVES
              // Compute the value of the error in the hessian at this
              // quadrature point
              if (_sobolev_order > 1)
                {
                  Tensor grad2_error = grad2_u_fine - grad2_u_coarse;

                  H2seminormsq += JxW[qp]*(grad2_error.contract(grad2_error));
                }
#endif

            } // end qp loop

          assert (L2normsq     >= 0.);
          assert (H1seminormsq >= 0.);

          error_per_cell[e_id] = L2normsq;
          if (_sobolev_order > 0)
            error_per_cell[e_id] += H1seminormsq;
          if (_sobolev_order > 1)
            error_per_cell[e_id] += H2seminormsq;

        } // End loop over active local elements
    } // End loop over variables

  // Uniformly coarsen the mesh, without projecting the solution
  old_projection_setting = system.project_solution_on_reinit();
  system.project_solution_on_reinit() = false;

  assert (number_h_refinements > 0 || number_p_refinements > 0);

  for (unsigned int i = 0; i != number_h_refinements; ++i)
    {
      mesh_refinement.uniformly_coarsen(1);
      // FIXME - should the reinits here be necessary? - RHS
      system.get_equation_systems().reinit();
    }

  for (unsigned int i = 0; i != number_p_refinements; ++i)
    {
      mesh_refinement.uniformly_p_coarsen(1);
      system.get_equation_systems().reinit();
    }

  system.project_solution_on_reinit() = old_projection_setting;

  // We should be back where we started
  assert(n_coarse_elem == mesh.n_elem());

  // Each processor has now computed the error contribuions
  // for its local elements.  We need to sum the vector
  // and then take the square-root of each component.  Note
  // that we only need to sum if we are running on multiple
  // processors, and we only need to take the square-root
  // if the value is nonzero.  There will in general be many
  // zeros for the inactive elements.

  // First sum the vector of estimated error values
  this->reduce_error(error_per_cell);

  // Compute the square-root of each component.
  START_LOG("std::sqrt()", "UniformRefinementEstimator");
  for (unsigned int i=0; i<error_per_cell.size(); i++)
    if (error_per_cell[i] != 0.)
      error_per_cell[i] = std::sqrt(error_per_cell[i]);
  STOP_LOG("std::sqrt()", "UniformRefinementEstimator");

  // Restore the coarse solution vectors and delete their copies
  for (System::vectors_iterator vec = system.vectors_begin(); vec !=
       system.vectors_end(); ++vec)
    {
      // The (string) name of this vector
      const std::string& var_name = vec->first;

      system.get_vector(var_name) = *coarse_vectors[var_name];

      coarse_vectors[var_name]->clear();
      delete coarse_vectors[var_name];
    }

  STOP_LOG("estimate_error()", "UniformRefinementEstimator");
}
<|endoftext|>