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

#include "cc/trees/layer_tree_host.h"

#include <sstream>

#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/nine_patch_layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer.h"
#include "cc/resources/texture_mailbox.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/lap_timer.h"
#include "cc/test/layer_tree_json_parser.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/paths.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/perf/perf_test.h"

namespace cc {
namespace {

static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;

class LayerTreeHostPerfTest : public LayerTreeTest {
 public:
  LayerTreeHostPerfTest()
      : draw_timer_(kWarmupRuns,
                    base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
                    kTimeCheckInterval),
        commit_timer_(0, base::TimeDelta(), 1),
        full_damage_each_frame_(false),
        animation_driven_drawing_(false),
        measure_commit_cost_(false) {
    fake_content_layer_client_.set_paint_all_opaque(true);
  }

  virtual void BeginTest() OVERRIDE {
    BuildTree();
    PostSetNeedsCommitToMainThread();
  }

  virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
    if (animation_driven_drawing_ && !TestEnded())
      layer_tree_host()->SetNeedsAnimate();
  }

  virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    if (measure_commit_cost_)
      commit_timer_.Start();
  }

  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    if (measure_commit_cost_ && draw_timer_.IsWarmedUp()) {
      commit_timer_.NextLap();
    }
  }

  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    if (TestEnded()) {
      return;
    }
    draw_timer_.NextLap();
    if (draw_timer_.HasTimeLimitExpired()) {
      EndTest();
      return;
    }
    if (!animation_driven_drawing_)
      impl->SetNeedsRedraw();
    if (full_damage_each_frame_)
      impl->SetFullRootLayerDamage();
  }

  virtual void BuildTree() {}

  virtual void AfterTest() OVERRIDE {
    CHECK(!test_name_.empty()) << "Must SetTestName() before AfterTest().";
    perf_test::PrintResult("layer_tree_host_frame_count", "", test_name_,
                           draw_timer_.NumLaps(), "frame_count", true);
    perf_test::PrintResult("layer_tree_host_frame_time", "", test_name_,
                           1000 * draw_timer_.MsPerLap(), "us", true);
    if (measure_commit_cost_) {
      perf_test::PrintResult("layer_tree_host_commit_count", "", test_name_,
                             commit_timer_.NumLaps(), "commit_count", true);
      perf_test::PrintResult("layer_tree_host_commit_time", "", test_name_,
                             1000 * commit_timer_.MsPerLap(), "us", true);
    }
  }

 protected:
  LapTimer draw_timer_;
  LapTimer commit_timer_;

  std::string test_name_;
  FakeContentLayerClient fake_content_layer_client_;
  bool full_damage_each_frame_;
  bool animation_driven_drawing_;

  bool measure_commit_cost_;
};

class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest {
 public:
  LayerTreeHostPerfTestJsonReader()
      : LayerTreeHostPerfTest() {
  }

  void SetTestName(const std::string& name) {
    test_name_ = name;
  }

  void ReadTestFile(const std::string& name) {
    base::FilePath test_data_dir;
    ASSERT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir));
    base::FilePath json_file = test_data_dir.AppendASCII(name + ".json");
    ASSERT_TRUE(base::ReadFileToString(json_file, &json_));
  }

  virtual void BuildTree() OVERRIDE {
    gfx::Size viewport = gfx::Size(720, 1038);
    layer_tree_host()->SetViewportSize(viewport);
    scoped_refptr<Layer> root = ParseTreeFromJson(json_,
                                                  &fake_content_layer_client_);
    ASSERT_TRUE(root.get());
    layer_tree_host()->SetRootLayer(root);
  }

 private:
  std::string json_;
};

// Simulates a tab switcher scene with two stacks of 10 tabs each.
TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) {
  SetTestName("10_10_single_thread");
  ReadTestFile("10_10_layer_tree");
  RunTest(false, false, false);
}

TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreadedImplSide) {
  SetTestName("10_10_threaded_impl_side");
  ReadTestFile("10_10_layer_tree");
  RunTestWithImplSidePainting();
}

// Simulates a tab switcher scene with two stacks of 10 tabs each.
TEST_F(LayerTreeHostPerfTestJsonReader,
       TenTenSingleThread_FullDamageEachFrame) {
  full_damage_each_frame_ = true;
  SetTestName("10_10_single_thread_full_damage_each_frame");
  ReadTestFile("10_10_layer_tree");
  RunTest(false, false, false);
}

TEST_F(LayerTreeHostPerfTestJsonReader,
       TenTenThreadedImplSide_FullDamageEachFrame) {
  full_damage_each_frame_ = true;
  SetTestName("10_10_threaded_impl_side_full_damage_each_frame");
  ReadTestFile("10_10_layer_tree");
  RunTestWithImplSidePainting();
}

// Invalidates a leaf layer in the tree on the main thread after every commit.
class LayerTreeHostPerfTestLeafInvalidates
    : public LayerTreeHostPerfTestJsonReader {
 public:
  virtual void BuildTree() OVERRIDE {
    LayerTreeHostPerfTestJsonReader::BuildTree();

    // Find a leaf layer.
    for (layer_to_invalidate_ = layer_tree_host()->root_layer();
         layer_to_invalidate_->children().size();
         layer_to_invalidate_ = layer_to_invalidate_->children()[0]) {}
  }

  virtual void DidCommitAndDrawFrame() OVERRIDE {
    if (TestEnded())
      return;

    static bool flip = true;
    layer_to_invalidate_->SetOpacity(flip ? 1.f : 0.5f);
    flip = !flip;
  }

 protected:
  Layer* layer_to_invalidate_;
};

// Simulates a tab switcher scene with two stacks of 10 tabs each. Invalidate a
// property on a leaf layer in the tree every commit.
TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) {
  SetTestName("10_10_single_thread_leaf_invalidates");
  ReadTestFile("10_10_layer_tree");
  RunTest(false, false, false);
}

TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreadedImplSide) {
  SetTestName("10_10_threaded_impl_side_leaf_invalidates");
  ReadTestFile("10_10_layer_tree");
  RunTestWithImplSidePainting();
}

// Simulates main-thread scrolling on each frame.
class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
 public:
  ScrollingLayerTreePerfTest()
      : LayerTreeHostPerfTestJsonReader() {
  }

  virtual void BuildTree() OVERRIDE {
    LayerTreeHostPerfTestJsonReader::BuildTree();
    scrollable_ = layer_tree_host()->root_layer()->children()[1];
    ASSERT_TRUE(scrollable_.get());
  }

  virtual void Layout() OVERRIDE {
    static const gfx::Vector2d delta = gfx::Vector2d(0, 10);
    scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta);
  }

 private:
  scoped_refptr<Layer> scrollable_;
};

TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) {
  SetTestName("long_scrollable_page");
  ReadTestFile("long_scrollable_page");
  RunTest(false, false, false);
}

TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) {
  SetTestName("long_scrollable_page_threaded_impl_side");
  ReadTestFile("long_scrollable_page");
  RunTestWithImplSidePainting();
}

static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}

// Simulates main-thread scrolling on each frame.
class BrowserCompositorInvalidateLayerTreePerfTest
    : public LayerTreeHostPerfTestJsonReader {
 public:
  BrowserCompositorInvalidateLayerTreePerfTest()
      : next_sync_point_(1) {
  }

  virtual void BuildTree() OVERRIDE {
    LayerTreeHostPerfTestJsonReader::BuildTree();
    tab_contents_ =
        static_cast<TextureLayer*>(
            layer_tree_host()->root_layer()->children()[0]->
                                             children()[0]->
                                             children()[0]->
                                             children()[0].get());
    ASSERT_TRUE(tab_contents_.get());
  }

  virtual void Layout() OVERRIDE {
    gpu::Mailbox gpu_mailbox;
    std::ostringstream name_stream;
    name_stream << "name" << next_sync_point_;
    const char* name = name_stream.str().c_str();
    memcpy(gpu_mailbox.name, name, strlen(name) + 1);
    scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
        base::Bind(&EmptyReleaseCallback));
    TextureMailbox mailbox(gpu_mailbox, next_sync_point_);
    next_sync_point_++;

    tab_contents_->SetTextureMailbox(mailbox, callback.Pass());
  }

 private:
  scoped_refptr<TextureLayer> tab_contents_;
  unsigned next_sync_point_;
};

TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) {
  SetTestName("dense_layer_tree");
  ReadTestFile("dense_layer_tree");
  RunTestWithImplSidePainting();
}

// Simulates a page with several large, transformed and animated layers.
TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) {
  animation_driven_drawing_ = true;
  measure_commit_cost_ = true;
  SetTestName("heavy_page");
  ReadTestFile("heavy_layer_tree");
  RunTestWithImplSidePainting();
}

class PageScaleImplSidePaintingPerfTest
    : public LayerTreeHostPerfTestJsonReader {
 public:
  PageScaleImplSidePaintingPerfTest()
      : max_scale_(16.f), min_scale_(1.f / max_scale_) {}

  virtual void SetupTree() OVERRIDE {
    layer_tree_host()->SetPageScaleFactorAndLimits(1.f, min_scale_, max_scale_);
  }

  virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
                                   float scale_delta) OVERRIDE {
    float page_scale_factor = layer_tree_host()->page_scale_factor();
    page_scale_factor *= scale_delta;
    layer_tree_host()->SetPageScaleFactorAndLimits(
        page_scale_factor, min_scale_, max_scale_);
  }

  virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
                             base::TimeTicks monotonic_time) OVERRIDE {
    if (!host_impl->pinch_gesture_active()) {
      host_impl->PinchGestureBegin();
      start_time_ = monotonic_time;
    }
    gfx::Point anchor(200, 200);

    float seconds = (monotonic_time - start_time_).InSecondsF();

    // Every half second, zoom from min scale to max scale.
    float interval = 0.5f;

    // Start time in the middle of the interval when zoom = 1.
    seconds += interval / 2.f;

    // Stack two ranges together to go up from min to max and down from
    // max to min in the next so as not to have a zoom discrepancy.
    float time_in_two_intervals = fmod(seconds, 2.f * interval) / interval;

    // Map everything to go from min to max between 0 and 1.
    float time_in_one_interval =
        time_in_two_intervals > 1.f ? 2.f - time_in_two_intervals
                                    : time_in_two_intervals;
    // Normalize time to -1..1.
    float normalized = 2.f * time_in_one_interval - 1.f;
    float scale_factor = std::abs(normalized) * (max_scale_ - 1.f) + 1.f;
    float total_scale = normalized < 0.f ? 1.f / scale_factor : scale_factor;

    float desired_delta =
        total_scale / host_impl->active_tree()->total_page_scale_factor();
    host_impl->PinchGestureUpdate(desired_delta, anchor);
  }

 private:
  float max_scale_;
  float min_scale_;
  base::TimeTicks start_time_;
};

TEST_F(PageScaleImplSidePaintingPerfTest, HeavyPage) {
  measure_commit_cost_ = true;
  SetTestName("heavy_page_page_scale");
  ReadTestFile("heavy_layer_tree");
  RunTestWithImplSidePainting();
}

}  // namespace
}  // namespace cc
<commit_msg>cc: Disable frame production throttling (vsync) in cc_perftests<commit_after>// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/trees/layer_tree_host.h"

#include <sstream>

#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/nine_patch_layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer.h"
#include "cc/resources/texture_mailbox.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/lap_timer.h"
#include "cc/test/layer_tree_json_parser.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/paths.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/perf/perf_test.h"

namespace cc {
namespace {

static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;

class LayerTreeHostPerfTest : public LayerTreeTest {
 public:
  LayerTreeHostPerfTest()
      : draw_timer_(kWarmupRuns,
                    base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
                    kTimeCheckInterval),
        commit_timer_(0, base::TimeDelta(), 1),
        full_damage_each_frame_(false),
        animation_driven_drawing_(false),
        measure_commit_cost_(false) {
    fake_content_layer_client_.set_paint_all_opaque(true);
  }

  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
    settings->throttle_frame_production = false;
  }

  virtual void BeginTest() OVERRIDE {
    BuildTree();
    PostSetNeedsCommitToMainThread();
  }

  virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
    if (animation_driven_drawing_ && !TestEnded())
      layer_tree_host()->SetNeedsAnimate();
  }

  virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    if (measure_commit_cost_)
      commit_timer_.Start();
  }

  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    if (measure_commit_cost_ && draw_timer_.IsWarmedUp()) {
      commit_timer_.NextLap();
    }
  }

  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    if (TestEnded()) {
      return;
    }
    draw_timer_.NextLap();
    if (draw_timer_.HasTimeLimitExpired()) {
      EndTest();
      return;
    }
    if (!animation_driven_drawing_)
      impl->SetNeedsRedraw();
    if (full_damage_each_frame_)
      impl->SetFullRootLayerDamage();
  }

  virtual void BuildTree() {}

  virtual void AfterTest() OVERRIDE {
    CHECK(!test_name_.empty()) << "Must SetTestName() before AfterTest().";
    perf_test::PrintResult("layer_tree_host_frame_count", "", test_name_,
                           draw_timer_.NumLaps(), "frame_count", true);
    perf_test::PrintResult("layer_tree_host_frame_time", "", test_name_,
                           1000 * draw_timer_.MsPerLap(), "us", true);
    if (measure_commit_cost_) {
      perf_test::PrintResult("layer_tree_host_commit_count", "", test_name_,
                             commit_timer_.NumLaps(), "commit_count", true);
      perf_test::PrintResult("layer_tree_host_commit_time", "", test_name_,
                             1000 * commit_timer_.MsPerLap(), "us", true);
    }
  }

 protected:
  LapTimer draw_timer_;
  LapTimer commit_timer_;

  std::string test_name_;
  FakeContentLayerClient fake_content_layer_client_;
  bool full_damage_each_frame_;
  bool animation_driven_drawing_;

  bool measure_commit_cost_;
};

class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest {
 public:
  LayerTreeHostPerfTestJsonReader()
      : LayerTreeHostPerfTest() {
  }

  void SetTestName(const std::string& name) {
    test_name_ = name;
  }

  void ReadTestFile(const std::string& name) {
    base::FilePath test_data_dir;
    ASSERT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir));
    base::FilePath json_file = test_data_dir.AppendASCII(name + ".json");
    ASSERT_TRUE(base::ReadFileToString(json_file, &json_));
  }

  virtual void BuildTree() OVERRIDE {
    gfx::Size viewport = gfx::Size(720, 1038);
    layer_tree_host()->SetViewportSize(viewport);
    scoped_refptr<Layer> root = ParseTreeFromJson(json_,
                                                  &fake_content_layer_client_);
    ASSERT_TRUE(root.get());
    layer_tree_host()->SetRootLayer(root);
  }

 private:
  std::string json_;
};

// Simulates a tab switcher scene with two stacks of 10 tabs each.
TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) {
  SetTestName("10_10_single_thread");
  ReadTestFile("10_10_layer_tree");
  RunTest(false, false, false);
}

TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreadedImplSide) {
  SetTestName("10_10_threaded_impl_side");
  ReadTestFile("10_10_layer_tree");
  RunTestWithImplSidePainting();
}

// Simulates a tab switcher scene with two stacks of 10 tabs each.
TEST_F(LayerTreeHostPerfTestJsonReader,
       TenTenSingleThread_FullDamageEachFrame) {
  full_damage_each_frame_ = true;
  SetTestName("10_10_single_thread_full_damage_each_frame");
  ReadTestFile("10_10_layer_tree");
  RunTest(false, false, false);
}

TEST_F(LayerTreeHostPerfTestJsonReader,
       TenTenThreadedImplSide_FullDamageEachFrame) {
  full_damage_each_frame_ = true;
  SetTestName("10_10_threaded_impl_side_full_damage_each_frame");
  ReadTestFile("10_10_layer_tree");
  RunTestWithImplSidePainting();
}

// Invalidates a leaf layer in the tree on the main thread after every commit.
class LayerTreeHostPerfTestLeafInvalidates
    : public LayerTreeHostPerfTestJsonReader {
 public:
  virtual void BuildTree() OVERRIDE {
    LayerTreeHostPerfTestJsonReader::BuildTree();

    // Find a leaf layer.
    for (layer_to_invalidate_ = layer_tree_host()->root_layer();
         layer_to_invalidate_->children().size();
         layer_to_invalidate_ = layer_to_invalidate_->children()[0]) {}
  }

  virtual void DidCommitAndDrawFrame() OVERRIDE {
    if (TestEnded())
      return;

    static bool flip = true;
    layer_to_invalidate_->SetOpacity(flip ? 1.f : 0.5f);
    flip = !flip;
  }

 protected:
  Layer* layer_to_invalidate_;
};

// Simulates a tab switcher scene with two stacks of 10 tabs each. Invalidate a
// property on a leaf layer in the tree every commit.
TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) {
  SetTestName("10_10_single_thread_leaf_invalidates");
  ReadTestFile("10_10_layer_tree");
  RunTest(false, false, false);
}

TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreadedImplSide) {
  SetTestName("10_10_threaded_impl_side_leaf_invalidates");
  ReadTestFile("10_10_layer_tree");
  RunTestWithImplSidePainting();
}

// Simulates main-thread scrolling on each frame.
class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
 public:
  ScrollingLayerTreePerfTest()
      : LayerTreeHostPerfTestJsonReader() {
  }

  virtual void BuildTree() OVERRIDE {
    LayerTreeHostPerfTestJsonReader::BuildTree();
    scrollable_ = layer_tree_host()->root_layer()->children()[1];
    ASSERT_TRUE(scrollable_.get());
  }

  virtual void Layout() OVERRIDE {
    static const gfx::Vector2d delta = gfx::Vector2d(0, 10);
    scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta);
  }

 private:
  scoped_refptr<Layer> scrollable_;
};

TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) {
  SetTestName("long_scrollable_page");
  ReadTestFile("long_scrollable_page");
  RunTest(false, false, false);
}

TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) {
  SetTestName("long_scrollable_page_threaded_impl_side");
  ReadTestFile("long_scrollable_page");
  RunTestWithImplSidePainting();
}

static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}

// Simulates main-thread scrolling on each frame.
class BrowserCompositorInvalidateLayerTreePerfTest
    : public LayerTreeHostPerfTestJsonReader {
 public:
  BrowserCompositorInvalidateLayerTreePerfTest()
      : next_sync_point_(1) {
  }

  virtual void BuildTree() OVERRIDE {
    LayerTreeHostPerfTestJsonReader::BuildTree();
    tab_contents_ =
        static_cast<TextureLayer*>(
            layer_tree_host()->root_layer()->children()[0]->
                                             children()[0]->
                                             children()[0]->
                                             children()[0].get());
    ASSERT_TRUE(tab_contents_.get());
  }

  virtual void Layout() OVERRIDE {
    gpu::Mailbox gpu_mailbox;
    std::ostringstream name_stream;
    name_stream << "name" << next_sync_point_;
    const char* name = name_stream.str().c_str();
    memcpy(gpu_mailbox.name, name, strlen(name) + 1);
    scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
        base::Bind(&EmptyReleaseCallback));
    TextureMailbox mailbox(gpu_mailbox, next_sync_point_);
    next_sync_point_++;

    tab_contents_->SetTextureMailbox(mailbox, callback.Pass());
  }

 private:
  scoped_refptr<TextureLayer> tab_contents_;
  unsigned next_sync_point_;
};

TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) {
  SetTestName("dense_layer_tree");
  ReadTestFile("dense_layer_tree");
  RunTestWithImplSidePainting();
}

// Simulates a page with several large, transformed and animated layers.
TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) {
  animation_driven_drawing_ = true;
  measure_commit_cost_ = true;
  SetTestName("heavy_page");
  ReadTestFile("heavy_layer_tree");
  RunTestWithImplSidePainting();
}

class PageScaleImplSidePaintingPerfTest
    : public LayerTreeHostPerfTestJsonReader {
 public:
  PageScaleImplSidePaintingPerfTest()
      : max_scale_(16.f), min_scale_(1.f / max_scale_) {}

  virtual void SetupTree() OVERRIDE {
    layer_tree_host()->SetPageScaleFactorAndLimits(1.f, min_scale_, max_scale_);
  }

  virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
                                   float scale_delta) OVERRIDE {
    float page_scale_factor = layer_tree_host()->page_scale_factor();
    page_scale_factor *= scale_delta;
    layer_tree_host()->SetPageScaleFactorAndLimits(
        page_scale_factor, min_scale_, max_scale_);
  }

  virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
                             base::TimeTicks monotonic_time) OVERRIDE {
    if (!host_impl->pinch_gesture_active()) {
      host_impl->PinchGestureBegin();
      start_time_ = monotonic_time;
    }
    gfx::Point anchor(200, 200);

    float seconds = (monotonic_time - start_time_).InSecondsF();

    // Every half second, zoom from min scale to max scale.
    float interval = 0.5f;

    // Start time in the middle of the interval when zoom = 1.
    seconds += interval / 2.f;

    // Stack two ranges together to go up from min to max and down from
    // max to min in the next so as not to have a zoom discrepancy.
    float time_in_two_intervals = fmod(seconds, 2.f * interval) / interval;

    // Map everything to go from min to max between 0 and 1.
    float time_in_one_interval =
        time_in_two_intervals > 1.f ? 2.f - time_in_two_intervals
                                    : time_in_two_intervals;
    // Normalize time to -1..1.
    float normalized = 2.f * time_in_one_interval - 1.f;
    float scale_factor = std::abs(normalized) * (max_scale_ - 1.f) + 1.f;
    float total_scale = normalized < 0.f ? 1.f / scale_factor : scale_factor;

    float desired_delta =
        total_scale / host_impl->active_tree()->total_page_scale_factor();
    host_impl->PinchGestureUpdate(desired_delta, anchor);
  }

 private:
  float max_scale_;
  float min_scale_;
  base::TimeTicks start_time_;
};

TEST_F(PageScaleImplSidePaintingPerfTest, HeavyPage) {
  measure_commit_cost_ = true;
  SetTestName("heavy_page_page_scale");
  ReadTestFile("heavy_layer_tree");
  RunTestWithImplSidePainting();
}

}  // namespace
}  // namespace cc
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include "pyobject.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include "pyfuture.hpp"
#include "pysignal.hpp"
#include "pyproperty.hpp"
#include "gil.hpp"
#include "error.hpp"
#include <qitype/dynamicobjectbuilder.hpp>
#include <qitype/jsoncodec.hpp>

qiLogCategory("qipy.object");

namespace qi { namespace py {

    boost::python::object importInspect() {
      static bool plouf = false;
      static boost::python::object& obj = *new boost::python::object;
      if (!plouf) {
        obj = boost::python::import("inspect");
        plouf = true;
      }
      return obj;
    }

    struct PyQiFunctor {
    public:
      PyQiFunctor(const std::string &funName, qi::AnyObject obj)
        : _object(obj)
        , _funName(funName)
      {}

      boost::python::object operator()(boost::python::tuple pyargs, boost::python::dict pykwargs) {
        qi::AnyValue val = qi::AnyValue::from(pyargs);
        bool async = boost::python::extract<bool>(pykwargs.get("_async", false));
        std::string funN = boost::python::extract<std::string>(pykwargs.get("_overload", _funName));
        qiLogDebug() << "calling a method: " << funN << " args:" << qi::encodeJSON(val);

        qi::Future<qi::AnyValue> fut;
        qi::Promise<qi::AnyValue> res(qi::FutureCallbackType_Sync);
        PyPromise pyprom(res);
        {
          //calling c++, so release the GIL.
          GILScopedUnlock _unlock;
          qi::Future<qi::AnyReference> fmeta = _object->metaCall(funN, val.asDynamic().asTupleValuePtr());
          //because futureAdapter support AnyRef containing Future<T>  (that will be converted to a Future<T>
          // instead of Future<Future<T>>
          fmeta.connect(boost::bind<void>(&detail::futureAdapter<qi::AnyValue>, _1, res));
          fut = res.future();
        }
        if (!async) {
          {
            //do not lock while waiting!
            GILScopedUnlock _unlock;
            fut.wait();
          }
          return fut.value().to<boost::python::object>();
        }
        return boost::python::object(pyprom.future());
      }

    public:
      qi::AnyObject _object;
      std::string   _funName;
    };

    void populateMethods(boost::python::object pyobj, qi::AnyObject obj) {
      qi::MetaObject::MethodMap           mm = obj->metaObject().methodMap();
      qi::MetaObject::MethodMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaMethod &mem = it->second;
        //drop special methods
        if (mem.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding method:" << mem.toString();
        boost::python::object fun = boost::python::raw_function(PyQiFunctor(mem.name().c_str(), obj));
        boost::python::api::setattr(pyobj, mem.name().c_str(), fun);
        // Fill __doc__ with Signature and description
        std::stringstream ssdocstring;
        ssdocstring << "Signature: " << mem.returnSignature().toString() << "\n";
        ssdocstring << mem.description();
        boost::python::object docstring(ssdocstring.str());
        boost::python::api::setattr(fun, "__doc__", docstring);
      }
    }

    void populateSignals(boost::python::object pyobj, qi::AnyObject obj) {
      qi::MetaObject::SignalMap           mm = obj->metaObject().signalMap();
      qi::MetaObject::SignalMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaSignal &ms = it->second;
        //drop special methods
        if (ms.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding signal:" << ms.toString();
        boost::python::object fun = qi::py::makePyProxySignal(obj, ms);
        boost::python::api::setattr(pyobj, ms.name(), fun);
      }
    }

    void populateProperties(boost::python::object pyobj, qi::AnyObject obj) {
      qi::MetaObject::PropertyMap           mm = obj->metaObject().propertyMap();
      qi::MetaObject::PropertyMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaProperty &mp = it->second;
        //drop special methods
        if (mp.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding property:" << mp.toString();
        boost::python::object fun = qi::py::makePyProxyProperty(obj, mp);
        boost::python::api::setattr(pyobj, mp.name().c_str(), fun);
      }
    }

    class PyQiObject {
    public:
      PyQiObject()
      {}

      PyQiObject(const qi::AnyObject &obj)
        : _object(obj)
      {}

      boost::python::object call(boost::python::str pyname, boost::python::tuple pyargs, boost::python::dict pykws) {
        return PyQiFunctor(boost::python::extract<std::string>(pyname), _object)(pyargs, pykws);
      }

      boost::python::object metaObject() {
        return qi::AnyReference(_object->metaObject()).to<boost::python::object>();
      }

      qi::AnyObject object() {
        return _object;
      }

    private:
      qi::AnyObject _object;
    };

    boost::python::object makePyQiObject(qi::AnyObject obj, const std::string &name) {
      boost::python::object result = boost::python::object(qi::py::PyQiObject(obj));
      qi::py::populateMethods(result, obj);
      qi::py::populateSignals(result, obj);
      qi::py::populateProperties(result, obj);
      return result;
    }

    //TODO: DO NOT DUPLICATE
    static qi::AnyReference pyCallMethod(const std::vector<qi::AnyReference>& cargs, boost::python::object callable) {
      qi::AnyReference gvret;
      try {
        qi::py::GILScopedLock _lock;
        boost::python::list   args;
        boost::python::object ret;

        std::vector<qi::AnyReference>::const_iterator it = cargs.begin();
        ++it; //drop the first arg which is DynamicObject*
        for (; it != cargs.end(); ++it) {
          qiLogDebug() << "argument: " << qi::encodeJSON(*it);
          args.append(it->to<boost::python::object>());
        }
        qiLogDebug() << "before method call";
        try {
          ret = callable(*boost::python::tuple(args));
        } catch (const boost::python::error_already_set &e) {
          std::string err = PyFormatError();
          qiLogDebug() << "call exception:" << err;
          throw std::runtime_error(err);
        }

        //convert python future to future, to allow the middleware to make magic with it.
        //serverresult will support async return value for call. (call returning future)
        boost::python::extract< PyFuture* > extractor(ret);
        if (extractor.check()) {
          PyFuture* pfut = extractor();
          if (pfut) { //pfut == 0, can mean ret is None.
            qiLogDebug() << "Future detected";
            qi::Future<qi::AnyValue> fut = *pfut;
            return qi::AnyReference(fut).clone();
          }
        }

        gvret = qi::AnyReference(ret).clone();
        qiLogDebug() << "method returned:" << qi::encodeJSON(gvret);

      } catch (const boost::python::error_already_set &e) {
        throw std::runtime_error("python failed");
      }
      return gvret;
    }

    //callback just needed to keep a ref on obj
    static void doNothing(qi::GenericObject *go, boost::python::object obj)
    {
      (void)go;
      (void)obj;
    }

    //get the signature for the function
    //if vargs => return m
    //else: return (m...m) with the good number of m
    std::string generateDefaultParamSignature(const std::string &key, boost::python::object& argspec)
    {
      //argspec[0] = args
      int argsz = boost::python::len(argspec[0]);

      //argspec[1] = name of vargs
      if (argspec[1])
      {
        //m is accept everything
        return "m";
      }

      if (argsz == 0) {
        std::stringstream serr;
        serr << "Method " << key << " is missing the self argument.";
        throw std::runtime_error(serr.str());
      }

      //drop self.
      argsz = argsz - 1;

      std::stringstream ss;

      ss << "(";
      for (int i = 0; i < argsz; ++i)
        ss << "m";
      ss << ")";
      return ss.str();
    }

    void registerMethod(qi::DynamicObjectBuilder& gob, const std::string& key, boost::python::object& method, const std::string& qisig)
    {
      qi::MetaMethodBuilder mmb;
      mmb.setName(key);
      boost::python::object desc = method.attr("__doc__");
      boost::python::object pyqiretsig = boost::python::getattr(method, "__qi_return_signature__", boost::python::object());
      if (desc)
        mmb.setDescription(boost::python::extract<std::string>(desc));
      boost::python::object inspect = importInspect();
      //returns: (args, varargs, keywords, defaults)
      boost::python::object tu = inspect.attr("getargspec")(method);

      std::string defparamsig = generateDefaultParamSignature(key, tu);

      qiLogDebug() << "Adding method: " << defparamsig;
      if (!qisig.empty())
        mmb.setParametersSignature(qisig);
      else
        mmb.setParametersSignature(defparamsig);

      std::string qiretsig;
      if (pyqiretsig) {
        qiretsig = boost::python::extract<std::string>(pyqiretsig);
      }

      if (!qiretsig.empty())
        mmb.setReturnSignature(qiretsig);
      else
        mmb.setReturnSignature("m");

      // Throw on error
      gob.xAdvertiseMethod(mmb, qi::AnyFunction::fromDynamicFunction(boost::bind(pyCallMethod, _1, method)));
    }

    qi::AnyObject makeQiAnyObject(boost::python::object obj)
    {
      //is that a qi::AnyObject?
      boost::python::extract<PyQiObject*> isthatyoumum(obj);

      if (isthatyoumum.check()) {
        qiLogDebug() << "this PyObject is already a qi::AnyObject. Just returning it.";
        return isthatyoumum()->object();
      }

      qi::DynamicObjectBuilder gob;
      //let the GIL handle the thread-safety for us
      gob.setThreadingModel(ObjectThreadingModel_MultiThread);
      GILScopedLock _lock;
      boost::python::object attrs(boost::python::borrowed(PyObject_Dir(obj.ptr())));

      for (int i = 0; i < boost::python::len(attrs); ++i) {
        std::string key = boost::python::extract<std::string>(attrs[i]);
        boost::python::object m = obj.attr(attrs[i]);

        boost::python::object pyqiname = boost::python::getattr(m, "__qi_name__", boost::python::object());
        boost::python::object pyqisig = boost::python::getattr(m, "__qi_signature__", boost::python::object());
        std::string qisig;

        if (pyqisig)
          qisig = boost::python::extract<std::string>(pyqisig);

        if (qisig == "DONOTBIND")
          continue;
        //override name by the one provide by @bind
        if (pyqiname)
          key = boost::python::extract<std::string>(pyqiname);

        if (PyMethod_Check(m.ptr())) {
          registerMethod(gob, key, m, qisig);

          continue;
        }

        //store a pointer on PySignal class
        static boost::python::object asignal = qi::py::makePySignal("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), asignal.ptr())) {
          qiLogDebug() << "Adding signal:" << key;
          gob.advertiseSignal(key, qi::py::getSignal(m));
          continue;
        }

        //TODO: check for Property
        static boost::python::object aproperty = qi::py::makePyProperty("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), aproperty.ptr())) {
          qiLogDebug() << "Adding property:" << key;
          gob.advertiseProperty(key, qi::py::getProperty(m));
          continue;
        }

      }
      //this is a useless callback, needed to keep a ref on obj.
      //when the GO is destructed, the ref is released.
      return gob.object(boost::bind<void>(&doNothing, _1, obj));
    }

    static boost::python::object pyobjectParamShrinker(boost::python::tuple args, boost::python::dict kwargs) {
      PyQiObject& pys = boost::python::extract<PyQiObject&>(args[0]);
      boost::python::list l;
      for (int i = 2; i < boost::python::len(args); ++i)
        l.append(args[i]);
      return pys.call(boost::python::extract<boost::python::str>(args[1]), boost::python::tuple(l), kwargs);
    }

    void export_pyobject() {
      boost::python::class_<qi::py::PyQiObject>("Object", boost::python::no_init)
          .def("call", boost::python::raw_function(&pyobjectParamShrinker, 1))
          //TODO: .def("post")
          //TODO: .def("setProperty")
          //TODO: .def("property")
          .def("metaObject", &qi::py::PyQiObject::metaObject);
      //import inspect in our current namespace
      importInspect();
    }
  }
}
<commit_msg>python: pyobject: support async<commit_after>/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include "pyobject.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include "pyfuture.hpp"
#include "pysignal.hpp"
#include "pyproperty.hpp"
#include "gil.hpp"
#include "error.hpp"
#include <qitype/dynamicobjectbuilder.hpp>
#include <qitype/jsoncodec.hpp>

qiLogCategory("qipy.object");

namespace qi { namespace py {

    boost::python::object importInspect() {
      static bool plouf = false;
      static boost::python::object& obj = *new boost::python::object;
      if (!plouf) {
        obj = boost::python::import("inspect");
        plouf = true;
      }
      return obj;
    }

    struct PyQiFunctor {
    public:
      PyQiFunctor(const std::string &funName, qi::AnyObject obj)
        : _object(obj)
        , _funName(funName)
      {}

      boost::python::object operator()(boost::python::tuple pyargs, boost::python::dict pykwargs) {
        qi::AnyValue val = qi::AnyValue::from(pyargs);
        bool async = boost::python::extract<bool>(pykwargs.get("_async", false));
        std::string funN = boost::python::extract<std::string>(pykwargs.get("_overload", _funName));
        qiLogDebug() << "calling a method: " << funN << " args:" << qi::encodeJSON(val);

        qi::Future<qi::AnyValue> fut;
        qi::Promise<qi::AnyValue> res(qi::FutureCallbackType_Sync);
        PyPromise pyprom(res);
        {
          //calling c++, so release the GIL.
          GILScopedUnlock _unlock;
          qi::Future<qi::AnyReference> fmeta = _object->metaCall(funN, val.asDynamic().asTupleValuePtr());
          //because futureAdapter support AnyRef containing Future<T>  (that will be converted to a Future<T>
          // instead of Future<Future<T>>
          fmeta.connect(boost::bind<void>(&detail::futureAdapter<qi::AnyValue>, _1, res));
          fut = res.future();
        }
        if (!async) {
          {
            //do not lock while waiting!
            GILScopedUnlock _unlock;
            fut.wait();
          }
          return fut.value().to<boost::python::object>();
        }
        return boost::python::object(pyprom.future());
      }

    public:
      qi::AnyObject _object;
      std::string   _funName;
    };

    void populateMethods(boost::python::object pyobj, qi::AnyObject obj) {
      qi::MetaObject::MethodMap           mm = obj->metaObject().methodMap();
      qi::MetaObject::MethodMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaMethod &mem = it->second;
        //drop special methods
        if (mem.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding method:" << mem.toString();
        boost::python::object fun = boost::python::raw_function(PyQiFunctor(mem.name().c_str(), obj));
        boost::python::api::setattr(pyobj, mem.name().c_str(), fun);
        // Fill __doc__ with Signature and description
        std::stringstream ssdocstring;
        ssdocstring << "Signature: " << mem.returnSignature().toString() << "\n";
        ssdocstring << mem.description();
        boost::python::object docstring(ssdocstring.str());
        boost::python::api::setattr(fun, "__doc__", docstring);
      }
    }

    void populateSignals(boost::python::object pyobj, qi::AnyObject obj) {
      qi::MetaObject::SignalMap           mm = obj->metaObject().signalMap();
      qi::MetaObject::SignalMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaSignal &ms = it->second;
        //drop special methods
        if (ms.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding signal:" << ms.toString();
        boost::python::object fun = qi::py::makePyProxySignal(obj, ms);
        boost::python::api::setattr(pyobj, ms.name(), fun);
      }
    }

    void populateProperties(boost::python::object pyobj, qi::AnyObject obj) {
      qi::MetaObject::PropertyMap           mm = obj->metaObject().propertyMap();
      qi::MetaObject::PropertyMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaProperty &mp = it->second;
        //drop special methods
        if (mp.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding property:" << mp.toString();
        boost::python::object fun = qi::py::makePyProxyProperty(obj, mp);
        boost::python::api::setattr(pyobj, mp.name().c_str(), fun);
      }
    }

    class PyQiObject {
    public:
      PyQiObject()
      {}

      PyQiObject(const qi::AnyObject &obj)
        : _object(obj)
      {}

      boost::python::object call(boost::python::str pyname, boost::python::tuple pyargs, boost::python::dict pykws) {
        return PyQiFunctor(boost::python::extract<std::string>(pyname), _object)(pyargs, pykws);
      }

      boost::python::object metaObject() {
        return qi::AnyReference(_object->metaObject()).to<boost::python::object>();
      }

      qi::AnyObject object() {
        return _object;
      }

    private:
      qi::AnyObject _object;
    };

    boost::python::object makePyQiObject(qi::AnyObject obj, const std::string &name) {
      boost::python::object result = boost::python::object(qi::py::PyQiObject(obj));
      qi::py::populateMethods(result, obj);
      qi::py::populateSignals(result, obj);
      qi::py::populateProperties(result, obj);
      return result;
    }

    //TODO: DO NOT DUPLICATE
    static qi::AnyReference pyCallMethod(const std::vector<qi::AnyReference>& cargs, boost::python::object callable) {
      qi::AnyReference gvret;
      try {
        qi::py::GILScopedLock _lock;
        boost::python::list   args;
        boost::python::object ret;

        std::vector<qi::AnyReference>::const_iterator it = cargs.begin();
        ++it; //drop the first arg which is DynamicObject*
        for (; it != cargs.end(); ++it) {
          qiLogDebug() << "argument: " << qi::encodeJSON(*it);
          args.append(it->to<boost::python::object>());
        }
        qiLogDebug() << "before method call";
        try {
          ret = callable(*boost::python::tuple(args));
        } catch (const boost::python::error_already_set &e) {
          std::string err = PyFormatError();
          qiLogDebug() << "call exception:" << err;
          throw std::runtime_error(err);
        }

        //convert python future to future, to allow the middleware to make magic with it.
        //serverresult will support async return value for call. (call returning future)
        boost::python::extract< PyFuture* > extractor(ret);
        if (extractor.check()) {
          PyFuture* pfut = extractor();
          if (pfut) { //pfut == 0, can mean ret is None.
            qiLogDebug() << "Future detected";
            qi::Future<qi::AnyValue> fut = *pfut;
            return qi::AnyReference(fut).clone();
          }
        }

        gvret = qi::AnyReference(ret).clone();
        qiLogDebug() << "method returned:" << qi::encodeJSON(gvret);

      } catch (const boost::python::error_already_set &e) {
        throw std::runtime_error("python failed");
      }
      return gvret;
    }

    //callback just needed to keep a ref on obj
    static void doNothing(qi::GenericObject *go, boost::python::object obj)
    {
      (void)go;
      (void)obj;
    }

    //get the signature for the function
    //if vargs => return m
    //else: return (m...m) with the good number of m
    std::string generateDefaultParamSignature(const std::string &key, boost::python::object& argspec)
    {
      //argspec[0] = args
      int argsz = boost::python::len(argspec[0]);

      //argspec[1] = name of vargs
      if (argspec[1])
      {
        //m is accept everything
        return "m";
      }

      if (argsz == 0) {
        std::stringstream serr;
        serr << "Method " << key << " is missing the self argument.";
        throw std::runtime_error(serr.str());
      }

      //drop self.
      argsz = argsz - 1;

      std::stringstream ss;

      ss << "(";
      for (int i = 0; i < argsz; ++i)
        ss << "m";
      ss << ")";
      return ss.str();
    }

    void registerMethod(qi::DynamicObjectBuilder& gob, const std::string& key, boost::python::object& method, const std::string& qisig)
    {
      qi::MetaMethodBuilder mmb;
      mmb.setName(key);
      boost::python::object desc = method.attr("__doc__");
      boost::python::object pyqiretsig = boost::python::getattr(method, "__qi_return_signature__", boost::python::object());
      if (desc)
        mmb.setDescription(boost::python::extract<std::string>(desc));
      boost::python::object inspect = importInspect();
      //returns: (args, varargs, keywords, defaults)
      boost::python::object tu = inspect.attr("getargspec")(method);

      std::string defparamsig = generateDefaultParamSignature(key, tu);

      qiLogDebug() << "Adding method: " << defparamsig;
      if (!qisig.empty())
        mmb.setParametersSignature(qisig);
      else
        mmb.setParametersSignature(defparamsig);

      std::string qiretsig;
      if (pyqiretsig) {
        qiretsig = boost::python::extract<std::string>(pyqiretsig);
      }

      if (!qiretsig.empty())
        mmb.setReturnSignature(qiretsig);
      else
        mmb.setReturnSignature("m");

      // Throw on error
      gob.xAdvertiseMethod(mmb, qi::AnyFunction::fromDynamicFunction(boost::bind(pyCallMethod, _1, method)));
    }

    qi::AnyObject makeQiAnyObject(boost::python::object obj)
    {
      //is that a qi::AnyObject?
      boost::python::extract<PyQiObject*> isthatyoumum(obj);

      if (isthatyoumum.check()) {
        qiLogDebug() << "this PyObject is already a qi::AnyObject. Just returning it.";
        return isthatyoumum()->object();
      }

      qi::DynamicObjectBuilder gob;
      //let the GIL handle the thread-safety for us
      gob.setThreadingModel(ObjectThreadingModel_MultiThread);
      GILScopedLock _lock;
      boost::python::object attrs(boost::python::borrowed(PyObject_Dir(obj.ptr())));

      for (int i = 0; i < boost::python::len(attrs); ++i) {
        std::string key = boost::python::extract<std::string>(attrs[i]);
        boost::python::object m = obj.attr(attrs[i]);

        boost::python::object pyqiname = boost::python::getattr(m, "__qi_name__", boost::python::object());
        boost::python::object pyqisig = boost::python::getattr(m, "__qi_signature__", boost::python::object());
        std::string qisig;

        if (pyqisig)
          qisig = boost::python::extract<std::string>(pyqisig);

        if (qisig == "DONOTBIND")
          continue;
        //override name by the one provide by @bind
        if (pyqiname)
          key = boost::python::extract<std::string>(pyqiname);

        if (PyMethod_Check(m.ptr())) {
          registerMethod(gob, key, m, qisig);

          continue;
        }

        //store a pointer on PySignal class
        static boost::python::object asignal = qi::py::makePySignal("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), asignal.ptr())) {
          qiLogDebug() << "Adding signal:" << key;
          gob.advertiseSignal(key, qi::py::getSignal(m));
          continue;
        }

        //TODO: check for Property
        static boost::python::object aproperty = qi::py::makePyProperty("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), aproperty.ptr())) {
          qiLogDebug() << "Adding property:" << key;
          gob.advertiseProperty(key, qi::py::getProperty(m));
          continue;
        }

      }
      //this is a useless callback, needed to keep a ref on obj.
      //when the GO is destructed, the ref is released.
      return gob.object(boost::bind<void>(&doNothing, _1, obj));
    }

    static boost::python::object pyobjectParamShrinker(boost::python::tuple args, boost::python::dict kwargs) {
      PyQiObject& pys = boost::python::extract<PyQiObject&>(args[0]);
      boost::python::list l;
      for (int i = 2; i < boost::python::len(args); ++i)
        l.append(args[i]);
      return pys.call(boost::python::extract<boost::python::str>(args[1]), boost::python::tuple(l), kwargs);
    }

    static boost::python::object pyobjectParamShrinkerAsync(boost::python::tuple args, boost::python::dict kwargs) {
      PyQiObject& pys = boost::python::extract<PyQiObject&>(args[0]);
      boost::python::list l;
      for (int i = 2; i < boost::python::len(args); ++i)
        l.append(args[i]);
      kwargs.attr("_async") = true;
      return pys.call(boost::python::extract<boost::python::str>(args[1]), boost::python::tuple(l), kwargs);
    }

    void export_pyobject() {
      boost::python::class_<qi::py::PyQiObject>("Object", boost::python::no_init)
          .def("call", boost::python::raw_function(&pyobjectParamShrinker, 1))
          .def("async", boost::python::raw_function(&pyobjectParamShrinkerAsync, 1))
          //TODO: .def("post")
          //TODO: .def("setProperty")
          //TODO: .def("property")
          .def("metaObject", &qi::py::PyQiObject::metaObject);
      //import inspect in our current namespace
      importInspect();
    }
  }
}
<|endoftext|>


<commit_before>#include <LoRa.h>

// registers
#define REG_FIFO                 0x00
#define REG_OP_MODE              0x01
#define REG_FRF_MSB              0x06
#define REG_FRF_MID              0x07
#define REG_FRF_LSB              0x08
#define REG_PA_CONFIG            0x09
#define REG_FIFO_ADDR_PTR        0x0d
#define REG_FIFO_TX_BASE_ADDR    0x0e
#define REG_FIFO_RX_BASE_ADDR    0x0f
#define REG_FIFO_RX_CURRENT_ADDR 0x10
#define REG_IRQ_FLAGS            0x12
#define REG_RX_NB_BYTES          0x13
#define REG_PKT_RSSI_VALUE       0x1a
#define REG_MODEM_CONFIG_1       0x1d
#define REG_MODEM_CONFIG_2       0x1e
#define REG_PREAMBLE_MSB         0x20
#define REG_PREAMBLE_LSB         0x21
#define REG_PAYLOAD_LENGTH       0x22
#define REG_DETECTION_OPTIMIZE   0x31
#define REG_DETECTION_THRESHOLD  0x37
#define REG_SYNC_WORD            0x39
#define REG_DIO_MAPPING_1        0x40
#define REG_VERSION              0x42

// modes
#define MODE_LONG_RANGE_MODE     0x80
#define MODE_SLEEP               0x00
#define MODE_STDBY               0x01
#define MODE_TX                  0x03
#define MODE_RX_CONTINUOUS       0x05
#define MODE_RX_SINGLE           0x06

// PA config
#define PA_BOOST                 0x80

// IRQ masks
#define IRQ_TX_DONE_MASK           0x08
#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20
#define IRQ_RX_DONE_MASK           0x40

#define MAX_PKT_LENGTH           255

LoRaClass::LoRaClass() :
  _spiSettings(10E6, MSBFIRST, SPI_MODE0),
  _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN),
  _frequency(0),
  _packetIndex(0),
  _onReceive(NULL)
{
}

int LoRaClass::begin(long frequency)
{
  // setup pins
  pinMode(_ss, OUTPUT);
  pinMode(_reset, OUTPUT);

  // perform reset
  digitalWrite(_reset, LOW);
  delay(10);
  digitalWrite(_reset, HIGH);
  delay(10);

  // set SS high
  digitalWrite(_ss, HIGH);

  // start SPI
  SPI.begin();

  // check version
  uint8_t version = readRegister(REG_VERSION);
  if (version != 0x12) {
    return 0;
  }

  // put in sleep mode
  sleep();

  // set frequency
  setFrequency(frequency);

  // set base addresses
  writeRegister(REG_FIFO_TX_BASE_ADDR, 0);
  writeRegister(REG_FIFO_RX_BASE_ADDR, 0);

  // set output power to 17 dBm
  setTxPower(17);

  // put in standby mode
  idle();

  return 1;
}

void LoRaClass::end()
{
  // put in sleep mode
  sleep();

  // stop SPI
  SPI.end();
}

int LoRaClass::beginPacket()
{
  // put in standby mode
  idle();

  // reset FIFO address and paload length
  writeRegister(REG_FIFO_ADDR_PTR, 0);
  writeRegister(REG_PAYLOAD_LENGTH, 0);

  return 1;
}

int LoRaClass::endPacket()
{
  // put in TX mode
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);

  // wait for TX done
  while((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0);

  // clear IRQ's
  writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);

  return 1;
}

int LoRaClass::parsePacket()
{
  int packetLength = 0;
  int irqFlags = readRegister(REG_IRQ_FLAGS);

  // clear IRQ's
  writeRegister(REG_IRQ_FLAGS, irqFlags);

  if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
    // received a packet
    _packetIndex = 0;

    // read packet length
    packetLength = readRegister(REG_RX_NB_BYTES);

    // set FIFO address to current RX address
    writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));

    // put in standby mode
    idle();
  } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) {
    // not currently in RX mode

    // reset FIFO address
    writeRegister(REG_FIFO_ADDR_PTR, 0);

    // put in single RX mode
    writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
  }

  return packetLength;
}

int LoRaClass::packetRssi()
{
  return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < 868E6 ? 164 : 157));
}

size_t LoRaClass::write(uint8_t byte)
{
  return write(&byte, sizeof(byte));
}

size_t LoRaClass::write(const uint8_t *buffer, size_t size)
{
  int currentLength = readRegister(REG_PAYLOAD_LENGTH);

  // check size
  if ((currentLength + size) > MAX_PKT_LENGTH) {
    size = MAX_PKT_LENGTH - currentLength;
  }

  // write data
  for (size_t i = 0; i < size; i++) {
    writeRegister(REG_FIFO, buffer[i]);
  }

  // update length
  writeRegister(REG_PAYLOAD_LENGTH, currentLength + size);

  return size;
}

int LoRaClass::available()
{
  return (readRegister(REG_RX_NB_BYTES) - _packetIndex);
}

int LoRaClass::read()
{
  if (!available()) {
    return -1;
  }

  _packetIndex++;

  return readRegister(REG_FIFO);
}

int LoRaClass::peek()
{
  if (!available()) {
    return -1;
  }

  // store current FIFO address
  int currentAddress = readRegister(REG_FIFO_ADDR_PTR);

  // read
  uint8_t b = readRegister(REG_FIFO);

  // restore FIFO address
  writeRegister(REG_FIFO_ADDR_PTR, currentAddress);

  return b;
}

void LoRaClass::flush()
{
}

void LoRaClass::onReceive(void(*callback)(int))
{
  _onReceive = callback;

  if (callback) {
    writeRegister(REG_DIO_MAPPING_1, 0x00);

    attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
  } else {
    detachInterrupt(digitalPinToInterrupt(_dio0));
  }
}

void LoRaClass::receive()
{
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
}

void LoRaClass::idle()
{
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY);
}

void LoRaClass::sleep()
{
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP);
}

void LoRaClass::setFrequency(long frequency)
{
  _frequency = frequency;

  uint64_t frf = ((uint64_t)frequency << 19) / 32000000;

  writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16));
  writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8));
  writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0));
}

void LoRaClass::setTxPower(int level)
{
  if (level < 2) {
    level = 2;
  } else if (level > 17) {
    level = 17;
  }

  writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2));
}

void LoRaClass::setSpreadingFactor(int sf)
{
  if (sf < 7) {
    sf = 7;
  } else if (sf > 12) {
    sf = 12;
  }

  writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe);
  writeRegister(REG_DETECTION_OPTIMIZE, 0xc3);
  writeRegister(REG_DETECTION_THRESHOLD, 0x0a);

  writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0));
}

void LoRaClass::setSignalBandwidth(long sbw)
{
  int bw;

  if (sbw <= 7.8E3) {
    bw = 0;
  } else if (sbw <= 10.4E3) {
    bw = 1;
  } else if (sbw <= 15.6E3) {
    bw = 2;
  } else if (sbw <= 20.8E3) {
    bw = 3;
  } else if (sbw <= 31.25E3) {
    bw = 4;
  } else if (sbw <= 41.7E3) {
    bw = 5;
  } else if (sbw <= 62.5E3) {
    bw = 6;
  } else if (sbw <= 125E3) {
    bw = 7;
  } else if (sbw <= 250E3) {
    bw = 8;
  } else /*if (sbw <= 250E3)*/ {
    bw = 9;
  }

  writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4));
}

void LoRaClass::setCodingRate4(int denominator)
{
  if (denominator < 5) {
    denominator = 5;
  } else if (denominator > 8) {
    denominator = 8;
  }

  int cr = denominator - 4;

  writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1));
}

void LoRaClass::setPreambleLength(unsigned long length)
{
  writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8));
  writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0));
}

void LoRaClass::setSyncWord(int sw)
{
  writeRegister(REG_SYNC_WORD, sw);
}

void LoRaClass::crc()
{
  writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04);
}

void LoRaClass::noCrc()
{
  writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb);
}

void LoRaClass::setPins(int ss, int reset, int dio0)
{
  _ss = ss;
  _reset = reset;
  _dio0 = dio0;
}

void LoRaClass::dumpRegisters(Stream& out)
{
  for (int i = 0; i < 128; i++) {
    out.print("0x");
    out.print(i, HEX);
    out.print(": 0x");
    out.println(readRegister(i), HEX);
  }
}

void LoRaClass::handleDio0Rise()
{
  int irqFlags = readRegister(REG_IRQ_FLAGS);

  // clear IRQ's
  writeRegister(REG_IRQ_FLAGS, irqFlags);

  if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
    // received a packet
    _packetIndex = 0;

    // read packet length
    int packetLength = readRegister(REG_RX_NB_BYTES);

    // set FIFO address to current RX address
    writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));

    if (_onReceive) {
      _onReceive(packetLength);
    }

    // reset FIFO address
    writeRegister(REG_FIFO_ADDR_PTR, 0);
  }
}

uint8_t LoRaClass::readRegister(uint8_t address)
{
  return singleTransfer(address & 0x7f, 0x00);
}

void LoRaClass::writeRegister(uint8_t address, uint8_t value)
{
  singleTransfer(address | 0x80, value);
}

uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value)
{
  uint8_t response;

  digitalWrite(_ss, LOW);

  SPI.beginTransaction(_spiSettings);
  SPI.transfer(address);
  response = SPI.transfer(value);
  SPI.endTransaction();

  digitalWrite(_ss, HIGH);

  return response;
}

void LoRaClass::onDio0Rise()
{
  LoRa.handleDio0Rise();
}

LoRaClass LoRa;
<commit_msg>Set LNA boost<commit_after>#include <LoRa.h>

// registers
#define REG_FIFO                 0x00
#define REG_OP_MODE              0x01
#define REG_FRF_MSB              0x06
#define REG_FRF_MID              0x07
#define REG_FRF_LSB              0x08
#define REG_PA_CONFIG            0x09
#define REG_LNA                  0x0c
#define REG_FIFO_ADDR_PTR        0x0d
#define REG_FIFO_TX_BASE_ADDR    0x0e
#define REG_FIFO_RX_BASE_ADDR    0x0f
#define REG_FIFO_RX_CURRENT_ADDR 0x10
#define REG_IRQ_FLAGS            0x12
#define REG_RX_NB_BYTES          0x13
#define REG_PKT_RSSI_VALUE       0x1a
#define REG_MODEM_CONFIG_1       0x1d
#define REG_MODEM_CONFIG_2       0x1e
#define REG_PREAMBLE_MSB         0x20
#define REG_PREAMBLE_LSB         0x21
#define REG_PAYLOAD_LENGTH       0x22
#define REG_DETECTION_OPTIMIZE   0x31
#define REG_DETECTION_THRESHOLD  0x37
#define REG_SYNC_WORD            0x39
#define REG_DIO_MAPPING_1        0x40
#define REG_VERSION              0x42

// modes
#define MODE_LONG_RANGE_MODE     0x80
#define MODE_SLEEP               0x00
#define MODE_STDBY               0x01
#define MODE_TX                  0x03
#define MODE_RX_CONTINUOUS       0x05
#define MODE_RX_SINGLE           0x06

// PA config
#define PA_BOOST                 0x80

// IRQ masks
#define IRQ_TX_DONE_MASK           0x08
#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20
#define IRQ_RX_DONE_MASK           0x40

#define MAX_PKT_LENGTH           255

LoRaClass::LoRaClass() :
  _spiSettings(10E6, MSBFIRST, SPI_MODE0),
  _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN),
  _frequency(0),
  _packetIndex(0),
  _onReceive(NULL)
{
}

int LoRaClass::begin(long frequency)
{
  // setup pins
  pinMode(_ss, OUTPUT);
  pinMode(_reset, OUTPUT);

  // perform reset
  digitalWrite(_reset, LOW);
  delay(10);
  digitalWrite(_reset, HIGH);
  delay(10);

  // set SS high
  digitalWrite(_ss, HIGH);

  // start SPI
  SPI.begin();

  // check version
  uint8_t version = readRegister(REG_VERSION);
  if (version != 0x12) {
    return 0;
  }

  // put in sleep mode
  sleep();

  // set frequency
  setFrequency(frequency);

  // set base addresses
  writeRegister(REG_FIFO_TX_BASE_ADDR, 0);
  writeRegister(REG_FIFO_RX_BASE_ADDR, 0);

  // set LNA boost
  writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03);

  // set output power to 17 dBm
  setTxPower(17);

  // put in standby mode
  idle();

  return 1;
}

void LoRaClass::end()
{
  // put in sleep mode
  sleep();

  // stop SPI
  SPI.end();
}

int LoRaClass::beginPacket()
{
  // put in standby mode
  idle();

  // reset FIFO address and paload length
  writeRegister(REG_FIFO_ADDR_PTR, 0);
  writeRegister(REG_PAYLOAD_LENGTH, 0);

  return 1;
}

int LoRaClass::endPacket()
{
  // put in TX mode
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);

  // wait for TX done
  while((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0);

  // clear IRQ's
  writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);

  return 1;
}

int LoRaClass::parsePacket()
{
  int packetLength = 0;
  int irqFlags = readRegister(REG_IRQ_FLAGS);

  // clear IRQ's
  writeRegister(REG_IRQ_FLAGS, irqFlags);

  if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
    // received a packet
    _packetIndex = 0;

    // read packet length
    packetLength = readRegister(REG_RX_NB_BYTES);

    // set FIFO address to current RX address
    writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));

    // put in standby mode
    idle();
  } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) {
    // not currently in RX mode

    // reset FIFO address
    writeRegister(REG_FIFO_ADDR_PTR, 0);

    // put in single RX mode
    writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
  }

  return packetLength;
}

int LoRaClass::packetRssi()
{
  return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < 868E6 ? 164 : 157));
}

size_t LoRaClass::write(uint8_t byte)
{
  return write(&byte, sizeof(byte));
}

size_t LoRaClass::write(const uint8_t *buffer, size_t size)
{
  int currentLength = readRegister(REG_PAYLOAD_LENGTH);

  // check size
  if ((currentLength + size) > MAX_PKT_LENGTH) {
    size = MAX_PKT_LENGTH - currentLength;
  }

  // write data
  for (size_t i = 0; i < size; i++) {
    writeRegister(REG_FIFO, buffer[i]);
  }

  // update length
  writeRegister(REG_PAYLOAD_LENGTH, currentLength + size);

  return size;
}

int LoRaClass::available()
{
  return (readRegister(REG_RX_NB_BYTES) - _packetIndex);
}

int LoRaClass::read()
{
  if (!available()) {
    return -1;
  }

  _packetIndex++;

  return readRegister(REG_FIFO);
}

int LoRaClass::peek()
{
  if (!available()) {
    return -1;
  }

  // store current FIFO address
  int currentAddress = readRegister(REG_FIFO_ADDR_PTR);

  // read
  uint8_t b = readRegister(REG_FIFO);

  // restore FIFO address
  writeRegister(REG_FIFO_ADDR_PTR, currentAddress);

  return b;
}

void LoRaClass::flush()
{
}

void LoRaClass::onReceive(void(*callback)(int))
{
  _onReceive = callback;

  if (callback) {
    writeRegister(REG_DIO_MAPPING_1, 0x00);

    attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
  } else {
    detachInterrupt(digitalPinToInterrupt(_dio0));
  }
}

void LoRaClass::receive()
{
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
}

void LoRaClass::idle()
{
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY);
}

void LoRaClass::sleep()
{
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP);
}

void LoRaClass::setFrequency(long frequency)
{
  _frequency = frequency;

  uint64_t frf = ((uint64_t)frequency << 19) / 32000000;

  writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16));
  writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8));
  writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0));
}

void LoRaClass::setTxPower(int level)
{
  if (level < 2) {
    level = 2;
  } else if (level > 17) {
    level = 17;
  }

  writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2));
}

void LoRaClass::setSpreadingFactor(int sf)
{
  if (sf < 7) {
    sf = 7;
  } else if (sf > 12) {
    sf = 12;
  }

  writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe);
  writeRegister(REG_DETECTION_OPTIMIZE, 0xc3);
  writeRegister(REG_DETECTION_THRESHOLD, 0x0a);

  writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0));
}

void LoRaClass::setSignalBandwidth(long sbw)
{
  int bw;

  if (sbw <= 7.8E3) {
    bw = 0;
  } else if (sbw <= 10.4E3) {
    bw = 1;
  } else if (sbw <= 15.6E3) {
    bw = 2;
  } else if (sbw <= 20.8E3) {
    bw = 3;
  } else if (sbw <= 31.25E3) {
    bw = 4;
  } else if (sbw <= 41.7E3) {
    bw = 5;
  } else if (sbw <= 62.5E3) {
    bw = 6;
  } else if (sbw <= 125E3) {
    bw = 7;
  } else if (sbw <= 250E3) {
    bw = 8;
  } else /*if (sbw <= 250E3)*/ {
    bw = 9;
  }

  writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4));
}

void LoRaClass::setCodingRate4(int denominator)
{
  if (denominator < 5) {
    denominator = 5;
  } else if (denominator > 8) {
    denominator = 8;
  }

  int cr = denominator - 4;

  writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1));
}

void LoRaClass::setPreambleLength(unsigned long length)
{
  writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8));
  writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0));
}

void LoRaClass::setSyncWord(int sw)
{
  writeRegister(REG_SYNC_WORD, sw);
}

void LoRaClass::crc()
{
  writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04);
}

void LoRaClass::noCrc()
{
  writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb);
}

void LoRaClass::setPins(int ss, int reset, int dio0)
{
  _ss = ss;
  _reset = reset;
  _dio0 = dio0;
}

void LoRaClass::dumpRegisters(Stream& out)
{
  for (int i = 0; i < 128; i++) {
    out.print("0x");
    out.print(i, HEX);
    out.print(": 0x");
    out.println(readRegister(i), HEX);
  }
}

void LoRaClass::handleDio0Rise()
{
  int irqFlags = readRegister(REG_IRQ_FLAGS);

  // clear IRQ's
  writeRegister(REG_IRQ_FLAGS, irqFlags);

  if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
    // received a packet
    _packetIndex = 0;

    // read packet length
    int packetLength = readRegister(REG_RX_NB_BYTES);

    // set FIFO address to current RX address
    writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));

    if (_onReceive) {
      _onReceive(packetLength);
    }

    // reset FIFO address
    writeRegister(REG_FIFO_ADDR_PTR, 0);
  }
}

uint8_t LoRaClass::readRegister(uint8_t address)
{
  return singleTransfer(address & 0x7f, 0x00);
}

void LoRaClass::writeRegister(uint8_t address, uint8_t value)
{
  singleTransfer(address | 0x80, value);
}

uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value)
{
  uint8_t response;

  digitalWrite(_ss, LOW);

  SPI.beginTransaction(_spiSettings);
  SPI.transfer(address);
  response = SPI.transfer(value);
  SPI.endTransaction();

  digitalWrite(_ss, HIGH);

  return response;
}

void LoRaClass::onDio0Rise()
{
  LoRa.handleDio0Rise();
}

LoRaClass LoRa;
<|endoftext|>


<commit_before>//
//  MCMC.cpp
//  EpiGenMCMC
//
//  Created by Lucy Li on 06/05/2016.
//  Copyright (c) 2016 Lucy Li, Imperial College London. All rights reserved.
//

#define MATHLIB_STANDALONE

#include <iostream>
#include "MCMC.h"

namespace EpiGenMCMC_MCMC {
    void initialise_logfile(std::string filename, Parameter model_params, MCMCoptions options, unsigned int seed1, unsigned int seed2) {
        std::chrono::time_point<std::chrono::system_clock> curr_time = std::chrono::system_clock::now();
        std::time_t start_time = std::chrono::system_clock::to_time_t(curr_time);
        std::cout << filename << std::endl;
        std::ofstream file(filename);
        file << "# Seeds: " << seed1 << ", " << seed2 << std::endl;
        file << "# Start time: " << std::ctime(&start_time) << std::endl;
        file << "# Starting parameters:" << std::endl;
        for (int i=0; i!=model_params.get_total_params(); ++i) {
            file << "#   " << model_params.getname(i) << " ";
            file << model_params.get(i) << std::endl;
        }
        file << "# MCMC details:" << std::endl;
        file << "#   " << options.iterations << " iterations" << std::endl;
        file << "#   " << options.particles << " particles" << std::endl;
        file << "#   Log parameters every " << options.log_every << " iterations" << std::endl;
        file << "#   Filter at most every " << options.pfilter_every << " time steps" << std::endl;
        file << "#   Filter if ESS < " << options.pfilter_threshold*100 << "% of particles" << std::endl;
        file << "#   Likelihood based on ";
        if (options.which_likelihood == 0) {
            file << "both epidemiologic and genealogical data";
            if (options.num_trees > 1) file << "(" << options.num_trees << " trees)";
        }
        else if (options.which_likelihood == 1) file << "epidemiologic data";
        else file << "genealogical data";
        file << std::endl;
        file << "state\tposterior\tlikelihood\tprior";
        for (int i=0; i!=model_params.get_total_params(); ++i) {
            if (model_params.is_estim(i)) file << "\t" << model_params.getname(i);
        }
        //        file << std::endl << "0";
        //        for (int i=0; i!=model_params.get_total_params(); ++i) {
        //            if (model_params.is_estim(i)) file << "\t" << model_params.get(i);
        //        }
        file << std::endl;
        file.close();
    }
    void mcmc_log(std::string filename, Parameter model_params, int iteration, double loglik, double logprior) {
        std::ofstream file(filename, std::ios::app);
        if (!std::isfinite(logprior)) logprior = -0.1*std::numeric_limits<double>::max();
        file << iteration << "\t" << loglik+logprior << "\t" << loglik << "\t" << logprior;
        for (int i=0; i!=model_params.get_total_params(); ++i) {
            if (model_params.is_estim(i)) file << "\t" << model_params.get(i);
        }
        file << std::endl;
        file.close();
    }
    void lhs(Parameter model_params, MCMCoptions options, std::vector <double> & lower_bounds, std::vector <double> & upper_bounds, int divides, int index_ML, bool verbose) {
        // Latin Hypercube Sampling
        double min_val;
        double max_val;
        double interval_size;
        double value;
        if (lower_bounds.size() < 1) { // First iteration of sampling
            for (int i=0; i!=model_params.get_total_params_to_estim(); ++i) {
                int j = model_params.get_estim_index(i);
                min_val = model_params.get_lower(j);
                max_val = model_params.get_upper(j);
                interval_size = (max_val - min_val) / (double) divides;
                for (int interval_i=0; interval_i!=divides; ++interval_i) {
                    value = min_val+(double)interval_i*interval_size;
                    lower_bounds.push_back(value);
                    upper_bounds.push_back(value+interval_size);
                }
            }
            if (verbose) std::cout << "Drawing a Latin Hypercube Sample for " << lower_bounds.size()/divides << " parameters ";
            if (verbose) std::cout << "each divided into " << divides << " partitions." << std::endl;
        }
        else {
            for (int i=0; i!=model_params.get_total_params_to_estim(); ++i) {
                int j = model_params.get_estim_index(i);
                min_val = lower_bounds[i*divides+index_ML];
                max_val = upper_bounds[i*divides+index_ML];
                interval_size = (max_val - min_val) / (double) divides;
                for (int interval_i=0; interval_i!=divides; ++interval_i) {
                    value = min_val+(double)interval_i*interval_size;
                    lower_bounds[i*divides+interval_i] = std::max(model_params.get_lower(j), value);
                    upper_bounds[i*divides+interval_i] = std::min(model_params.get_upper(j), value+interval_size);
                }
            }
        }
        std::vector <int> indices (divides);
        for (int i=0; i!=divides; ++i) indices[i] = i;
        int param_index;
        std::vector <double> lowers_matrix (lower_bounds.size());
        std::vector <double> uppers_matrix = lowers_matrix;
        // Construct grid of parameter value combinations to calculate the likelihood
        for (int i=0; i!=model_params.get_total_params_to_estim(); ++i) {
            gsl_ran_shuffle(options.rng[0], &indices[0], indices.size(), sizeof(int));
            for (int j=0; j!=indices.size(); ++j) {
                param_index = i*divides+indices[j];
                lowers_matrix[i*divides+j] = lower_bounds[param_index];
                uppers_matrix[i*divides+j] = upper_bounds[param_index];
            }
        }
        lowers_matrix.swap(lower_bounds);
        uppers_matrix.swap(upper_bounds);
    }
    int mcmc (Parameter & model_params, MCMCoptions & options, Trajectory & traj, TimeSeriesData & epi_data, TreeData & tree_data, MultiTreeData & multitree_data) {
        if (options.verbose) std::cout << "Begin MCMC" << std::endl;
        if (options.verbose) std::cout << "Using " << options.num_threads << " cores." << std::endl;
        unsigned int seed1 = (int)time(0);
        unsigned int seed2 = (int)time(0)+10;
        options.seed = seed1;
        const gsl_rng_type * rng_t = gsl_rng_rand;
        gsl_rng **rng;
        rng = (gsl_rng **) malloc(options.num_threads * sizeof(gsl_rng *));
        for (int i = 0; i != options.num_threads; ++i) {
            rng[i] = gsl_rng_alloc(rng_t);
            gsl_rng_set(rng[i], seed1+i);
        }
        options.rng = rng;
        initialise_logfile(options.log_filename, model_params, options, seed1, seed2);
        if (options.verbose) std::cout << "MCMC log file initialised" << std::endl;
        double loglik;
        double newloglik;
        double prior_ratio;
        double correction_factor;
        double accept_with_prob;
        double ran_num;
        bool accept;
        Trajectory temptraj = traj;
        Particle particles(options.particles, traj);
        Model sim_model;
        if (options.use_lhs) {
            bool save_traj_in_mcmc_chain = options.save_traj;
            if (options.save_traj) options.save_traj = false;
            std::vector <double> lower_bounds;
            std::vector <double> upper_bounds;
            int index_max = 0;
            for (int i=0; i!=options.lhs_iterations; ++i) {
                if (options.verbose) std::cout << "Iteration 1" << std::endl;
                lhs(model_params, options, lower_bounds, upper_bounds, options.lhs_divides, index_max, options.verbose);
                double loglik = -std::numeric_limits<double>::max();
                double max_posterior = loglik;
                for (int j=0; j!=options.lhs_divides; ++j) {
                    if (options.verbose) std::cout << j << ") ";
                    // Set parameter values to the next combination
                    for (int param_i=0; param_i!=model_params.get_total_params_to_estim(); ++param_i) {
                        int curr_param_index = model_params.get_estim_index(param_i);
                        int grid_index = param_i*options.lhs_divides+j;
                        double curr_param_value = (lower_bounds[grid_index]+upper_bounds[grid_index])/2.0;
                        model_params.set(curr_param_index, curr_param_value);
                        model_params.transform_param(curr_param_index, true);
                        std::cout << model_params.get(curr_param_index) << " ";
                    }
                    // Likelihood of current parameter combination
//                    loglik = -std::numeric_limits<double>::max();
                    loglik = EpiGenPfilter::pfilter(sim_model, model_params, options, particles, temptraj, epi_data, tree_data, multitree_data);
                    if (options.verbose) std::cout << "loglik: " << loglik << std::endl;
                    if (j==0) {
                        max_posterior = loglik + model_params.get_prior_all();
                        index_max = 0;
                    }
                    else {
                        if (loglik + model_params.get_prior_all() > max_posterior) {
                            // If a new maximum posterior density is found, update index_ML
                            // to the index of the current parameter combination
                            index_max = j;
                            max_posterior = loglik + model_params.get_prior_all();
                        }
                    }
                }
            }
            // Set initial parameter values to those that produced the maximum posterior density
            for (int param_i=0; param_i!=model_params.get_total_params_to_estim(); ++param_i) {
                int curr_param_index = model_params.get_estim_index(param_i);
                int grid_index = param_i*options.lhs_divides+index_max;
                double curr_param_value = (lower_bounds[grid_index]+upper_bounds[grid_index])/2.0;
                model_params.set(curr_param_index, curr_param_value);
                model_params.transform_param(curr_param_index, true);
            }
            if (save_traj_in_mcmc_chain) options.save_traj = true;
        }
        std::chrono::time_point<std::chrono::system_clock> time1 = std::chrono::system_clock::now(), time2;
        std::chrono::duration<double> elapsed_seconds;
        if (options.verbose) time1 = std::chrono::system_clock::now();
        loglik = EpiGenPfilter::pfilter(sim_model, model_params, options, particles, traj, epi_data, tree_data, multitree_data);
        if (options.verbose) {
            time2 = std::chrono::system_clock::now();
            elapsed_seconds = time2-time1;
            time1 = time2;
            std::cout << "State TimeInterval Acceptance" << std::endl;
            std::cout << "0 " << elapsed_seconds.count() << " 0.0"<< std::endl;
        }
        if (options.save_traj) traj.print_to_file(0, options.traj_filename, options.pfilter_every, true);
        mcmc_log(options.log_filename, model_params, 0, loglik, model_params.get_prior_all());
        for (int iter = 1; iter != options.iterations; ++iter) {
            correction_factor = model_params.propose(options.rng[0]);
            particles.reset_weights();
            newloglik = EpiGenPfilter::pfilter(sim_model, model_params, options, particles, temptraj, epi_data, tree_data, multitree_data);
            prior_ratio = model_params.get_prior_ratio();
            accept_with_prob = (newloglik - loglik) + prior_ratio + correction_factor;
            accept = accept_with_prob >= 0.0;
            if (!accept) {
                ran_num = gsl_rng_uniform(options.rng[0]);
                if (log(ran_num) < accept_with_prob) accept = true;
            }
            if (accept) {
                loglik = newloglik;
                model_params.accept();
                traj = temptraj;
            }
            else {
                model_params.reject();
            }
            if ((iter)%options.log_every == 0) {
                if (options.save_traj) traj.print_to_file(iter, options.traj_filename, options.pfilter_every, true);
                mcmc_log(options.log_filename, model_params, iter, loglik, model_params.get_prior_all());
                if (options.verbose) {
                    time2 = std::chrono::system_clock::now();
                    elapsed_seconds = time2-time1;
                    time1 = time2;
                    std::cout << iter << " " << elapsed_seconds.count() << " ";
                    std::cout << model_params.get_acceptance() << std::endl;
                }
            }
        }
        particles.clear();
        return (1);
    }
}
<commit_msg>added chain heating and cooling<commit_after>//
//  MCMC.cpp
//  EpiGenMCMC
//
//  Created by Lucy Li on 06/05/2016.
//  Copyright (c) 2016 Lucy Li, Imperial College London. All rights reserved.
//

#define MATHLIB_STANDALONE

#include <iostream>
#include "MCMC.h"

namespace EpiGenMCMC_MCMC {
    void initialise_logfile(std::string filename, Parameter model_params, MCMCoptions options, unsigned int seed1, unsigned int seed2) {
        std::chrono::time_point<std::chrono::system_clock> curr_time = std::chrono::system_clock::now();
        std::time_t start_time = std::chrono::system_clock::to_time_t(curr_time);
        std::cout << filename << std::endl;
        std::ofstream file(filename);
        file << "# Seeds: " << seed1 << ", " << seed2 << std::endl;
        file << "# Start time: " << std::ctime(&start_time) << std::endl;
        file << "# Starting parameters:" << std::endl;
        for (int i=0; i!=model_params.get_total_params(); ++i) {
            file << "#   " << model_params.getname(i) << " ";
            file << model_params.get(i) << std::endl;
        }
        file << "# MCMC details:" << std::endl;
        file << "#   " << options.iterations << " iterations" << std::endl;
        file << "#   " << options.particles << " particles" << std::endl;
        file << "#   Log parameters every " << options.log_every << " iterations" << std::endl;
        file << "#   Filter at most every " << options.pfilter_every << " time steps" << std::endl;
        file << "#   Filter if ESS < " << options.pfilter_threshold*100 << "% of particles" << std::endl;
        file << "#   Likelihood based on ";
        if (options.which_likelihood == 0) {
            file << "both epidemiologic and genealogical data";
            if (options.num_trees > 1) file << "(" << options.num_trees << " trees)";
        }
        else if (options.which_likelihood == 1) file << "epidemiologic data";
        else file << "genealogical data";
        file << std::endl;
        file << "state\tposterior\tlikelihood\tprior";
        for (int i=0; i!=model_params.get_total_params(); ++i) {
            if (model_params.is_estim(i)) file << "\t" << model_params.getname(i);
        }
        //        file << std::endl << "0";
        //        for (int i=0; i!=model_params.get_total_params(); ++i) {
        //            if (model_params.is_estim(i)) file << "\t" << model_params.get(i);
        //        }
        file << std::endl;
        file.close();
    }
    void mcmc_log(std::string filename, Parameter model_params, int iteration, double loglik, double logprior) {
        std::ofstream file(filename, std::ios::app);
        if (!std::isfinite(logprior)) logprior = -0.1*std::numeric_limits<double>::max();
        file << iteration << "\t" << loglik+logprior << "\t" << loglik << "\t" << logprior;
        for (int i=0; i!=model_params.get_total_params(); ++i) {
            if (model_params.is_estim(i)) file << "\t" << model_params.get(i);
        }
        file << std::endl;
        file.close();
    }
    void lhs(Parameter model_params, MCMCoptions options, std::vector <double> & lower_bounds, std::vector <double> & upper_bounds, int divides, int index_ML, bool verbose) {
        // Latin Hypercube Sampling
        double min_val;
        double max_val;
        double interval_size;
        double value;
        if (lower_bounds.size() < 1) { // First iteration of sampling
            for (int i=0; i!=model_params.get_total_params_to_estim(); ++i) {
                int j = model_params.get_estim_index(i);
                min_val = model_params.get_lower(j);
                max_val = model_params.get_upper(j);
                interval_size = (max_val - min_val) / (double) divides;
                for (int interval_i=0; interval_i!=divides; ++interval_i) {
                    value = min_val+(double)interval_i*interval_size;
                    lower_bounds.push_back(value);
                    upper_bounds.push_back(value+interval_size);
                }
            }
            if (verbose) std::cout << "Drawing a Latin Hypercube Sample for " << lower_bounds.size()/divides << " parameters ";
            if (verbose) std::cout << "each divided into " << divides << " partitions." << std::endl;
        }
        else {
            for (int i=0; i!=model_params.get_total_params_to_estim(); ++i) {
                int j = model_params.get_estim_index(i);
                min_val = lower_bounds[i*divides+index_ML];
                max_val = upper_bounds[i*divides+index_ML];
                interval_size = (max_val - min_val) / (double) divides;
                for (int interval_i=0; interval_i!=divides; ++interval_i) {
                    value = min_val+(double)interval_i*interval_size;
                    lower_bounds[i*divides+interval_i] = std::max(model_params.get_lower(j), value);
                    upper_bounds[i*divides+interval_i] = std::min(model_params.get_upper(j), value+interval_size);
                }
            }
        }
        std::vector <int> indices (divides);
        for (int i=0; i!=divides; ++i) indices[i] = i;
        int param_index;
        std::vector <double> lowers_matrix (lower_bounds.size());
        std::vector <double> uppers_matrix = lowers_matrix;
        // Construct grid of parameter value combinations to calculate the likelihood
        for (int i=0; i!=model_params.get_total_params_to_estim(); ++i) {
            gsl_ran_shuffle(options.rng[0], &indices[0], indices.size(), sizeof(int));
            for (int j=0; j!=indices.size(); ++j) {
                param_index = i*divides+indices[j];
                lowers_matrix[i*divides+j] = lower_bounds[param_index];
                uppers_matrix[i*divides+j] = upper_bounds[param_index];
            }
        }
        lowers_matrix.swap(lower_bounds);
        uppers_matrix.swap(upper_bounds);
    }
    int mcmc (Parameter & model_params, MCMCoptions & options, Trajectory & traj, TimeSeriesData & epi_data, TreeData & tree_data, MultiTreeData & multitree_data) {
        if (options.verbose) std::cout << "Begin MCMC" << std::endl;
        if (options.verbose) std::cout << "Using " << options.num_threads << " cores." << std::endl;
        unsigned int seed1 = (int)time(0);
        unsigned int seed2 = (int)time(0)+10;
        options.seed = seed1;
        const gsl_rng_type * rng_t = gsl_rng_rand;
        gsl_rng **rng;
        rng = (gsl_rng **) malloc(options.num_threads * sizeof(gsl_rng *));
        for (int i = 0; i != options.num_threads; ++i) {
            rng[i] = gsl_rng_alloc(rng_t);
            gsl_rng_set(rng[i], seed1+i);
        }
        options.rng = rng;
        initialise_logfile(options.log_filename, model_params, options, seed1, seed2);
        if (options.verbose) std::cout << "MCMC log file initialised" << std::endl;
        double loglik;
        double newloglik;
        double prior_ratio;
        double correction_factor;
        double accept_with_prob;
        double ran_num;
        bool accept;
        Trajectory temptraj = traj;
        Particle particles(options.particles, traj);
        Model sim_model;
        if (options.use_lhs) {
            bool save_traj_in_mcmc_chain = options.save_traj;
            if (options.save_traj) options.save_traj = false;
            std::vector <double> lower_bounds;
            std::vector <double> upper_bounds;
            int index_max = 0;
            for (int i=0; i!=options.lhs_iterations; ++i) {
                if (options.verbose) std::cout << "Iteration 1" << std::endl;
                lhs(model_params, options, lower_bounds, upper_bounds, options.lhs_divides, index_max, options.verbose);
                double loglik = -std::numeric_limits<double>::max();
                double max_posterior = loglik;
                for (int j=0; j!=options.lhs_divides; ++j) {
                    if (options.verbose) std::cout << j << ") ";
                    // Set parameter values to the next combination
                    for (int param_i=0; param_i!=model_params.get_total_params_to_estim(); ++param_i) {
                        int curr_param_index = model_params.get_estim_index(param_i);
                        int grid_index = param_i*options.lhs_divides+j;
                        double curr_param_value = (lower_bounds[grid_index]+upper_bounds[grid_index])/2.0;
                        model_params.set(curr_param_index, curr_param_value);
                        model_params.transform_param(curr_param_index, true);
                        std::cout << model_params.get(curr_param_index) << " ";
                    }
                    // Likelihood of current parameter combination
//                    loglik = -std::numeric_limits<double>::max();
                    loglik = EpiGenPfilter::pfilter(sim_model, model_params, options, particles, temptraj, epi_data, tree_data, multitree_data);
                    if (options.verbose) std::cout << "loglik: " << loglik << std::endl;
                    if (j==0) {
                        max_posterior = loglik + model_params.get_prior_all();
                        index_max = 0;
                    }
                    else {
                        if (loglik + model_params.get_prior_all() > max_posterior) {
                            // If a new maximum posterior density is found, update index_ML
                            // to the index of the current parameter combination
                            index_max = j;
                            max_posterior = loglik + model_params.get_prior_all();
                        }
                    }
                }
            }
            // Set initial parameter values to those that produced the maximum posterior density
            for (int param_i=0; param_i!=model_params.get_total_params_to_estim(); ++param_i) {
                int curr_param_index = model_params.get_estim_index(param_i);
                int grid_index = param_i*options.lhs_divides+index_max;
                double curr_param_value = (lower_bounds[grid_index]+upper_bounds[grid_index])/2.0;
                model_params.set(curr_param_index, curr_param_value);
                model_params.transform_param(curr_param_index, true);
            }
            if (save_traj_in_mcmc_chain) options.save_traj = true;
        }
        std::chrono::time_point<std::chrono::system_clock> time1 = std::chrono::system_clock::now(), time2;
        std::chrono::duration<double> elapsed_seconds;
        if (options.verbose) time1 = std::chrono::system_clock::now();
        loglik = EpiGenPfilter::pfilter(sim_model, model_params, options, particles, traj, epi_data, tree_data, multitree_data);
        if (options.verbose) {
            time2 = std::chrono::system_clock::now();
            elapsed_seconds = time2-time1;
            time1 = time2;
            std::cout << "State TimeInterval Acceptance" << std::endl;
            std::cout << "0 " << elapsed_seconds.count() << " 0.0"<< std::endl;
        }
        if (options.save_traj) traj.print_to_file(0, options.traj_filename, options.pfilter_every, true);
        mcmc_log(options.log_filename, model_params, 0, loglik, model_params.get_prior_all());
        for (int iter = 1; iter != options.iterations; ++iter) {
            correction_factor = model_params.propose(options.rng[0]);
            particles.reset_weights();
            newloglik = EpiGenPfilter::pfilter(sim_model, model_params, options, particles, temptraj, epi_data, tree_data, multitree_data);
            prior_ratio = model_params.get_prior_ratio();
            accept_with_prob = (newloglik - loglik) + prior_ratio + correction_factor;
            if (options.heat_length > 0) {
                if (iter <= (options.heat_length*model_params.get_total_params())) accept_with_prob += log(options.heat_factor);
                else {
                    if ((iter % model_params.get_total_params())==0) {
                        if (options.heat_factor > 1.0) {
                            options.heat_factor -= std::min(options.heat_factor-1.0, options.cool_rate);
                            accept_with_prob += log(options.heat_factor);
                        }
                        else {
                            model_params.start_adapt();
                        }
                    }
                }
            }
            accept = accept_with_prob >= 0.0;
            if (!accept) {
                ran_num = gsl_rng_uniform(options.rng[0]);
                if (log(ran_num) < accept_with_prob) accept = true;
            }
            if (accept) {
                loglik = newloglik;
                traj = temptraj;
                model_params.accept();
            }
            else {
                model_params.reject();
            }
            if ((iter)%options.log_every == 0) {
                if (options.save_traj) traj.print_to_file(iter, options.traj_filename, options.pfilter_every, true);
                mcmc_log(options.log_filename, model_params, iter, loglik, model_params.get_prior_all());
                if (options.verbose) {
                    time2 = std::chrono::system_clock::now();
                    elapsed_seconds = time2-time1;
                    time1 = time2;
                    std::cout << iter << " " << elapsed_seconds.count() << " ";
                    std::cout << model_params.get_acceptance() << std::endl;
                }
            }
        }
        particles.clear();
        return (1);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE gnode_test
#include <boost/test/unit_test.hpp>
#include <votca/xtp/atom.h>

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(atom_test)

BOOST_AUTO_TEST_CASE(constructors_test) { Atom atm(1, "C"); }

BOOST_AUTO_TEST_CASE(getters_test) {
    Atom atm(3,"H");
    BOOST_CHECK_EQUAL(atm.getId(),3);
    BOOST_CHECK_EQUAL(atm.getName(),"H");
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Added formatting to test_atom file<commit_after>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE gnode_test
#include <boost/test/unit_test.hpp>
#include <votca/xtp/atom.h>

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(atom_test)

BOOST_AUTO_TEST_CASE(constructors_test) { Atom atm(1, "C"); }

BOOST_AUTO_TEST_CASE(getters_test) {
  Atom atm(3, "H");
  BOOST_CHECK_EQUAL(atm.getId(), 3);
  BOOST_CHECK_EQUAL(atm.getName(), "H");
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>