<commit_before>// Copyright (c) 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 <string>

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/background/background_contents_service.h"
#include "chrome/browser/background/background_contents_service_factory.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/extensions/extension_test_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_browser_thread.h"
#include "extensions/common/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "url/gurl.h"

#if defined(ENABLE_NOTIFICATIONS)
#include "chrome/browser/notifications/message_center_notification_manager.h"
#include "chrome/browser/notifications/notification.h"
#include "ui/message_center/fake_message_center_tray_delegate.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_observer.h"
#endif

class BackgroundContentsServiceTest : public testing::Test {
 public:
  BackgroundContentsServiceTest() {}
  virtual ~BackgroundContentsServiceTest() {}
  virtual void SetUp() {
    command_line_.reset(new CommandLine(CommandLine::NO_PROGRAM));
  }

  const base::DictionaryValue* GetPrefs(Profile* profile) {
    return profile->GetPrefs()->GetDictionary(
        prefs::kRegisteredBackgroundContents);
  }

  // Returns the stored pref URL for the passed app id.
  std::string GetPrefURLForApp(Profile* profile, const base::string16& appid) {
    const base::DictionaryValue* pref = GetPrefs(profile);
    EXPECT_TRUE(pref->HasKey(base::UTF16ToUTF8(appid)));
    const base::DictionaryValue* value;
    pref->GetDictionaryWithoutPathExpansion(base::UTF16ToUTF8(appid), &value);
    std::string url;
    value->GetString("url", &url);
    return url;
  }

  scoped_ptr<CommandLine> command_line_;
};

class MockBackgroundContents : public BackgroundContents {
 public:
  explicit MockBackgroundContents(Profile* profile)
      : appid_(base::ASCIIToUTF16("app_id")),
        profile_(profile) {
  }
  MockBackgroundContents(Profile* profile, const std::string& id)
      : appid_(base::ASCIIToUTF16(id)),
        profile_(profile) {
  }

  void SendOpenedNotification(BackgroundContentsService* service) {
    base::string16 frame_name = base::ASCIIToUTF16("background");
    BackgroundContentsOpenedDetails details = {
        this, frame_name, appid_ };
    service->BackgroundContentsOpened(&details);
  }

  virtual void Navigate(GURL url) {
    url_ = url;
    content::NotificationService::current()->Notify(
        chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
        content::Source<Profile>(profile_),
        content::Details<BackgroundContents>(this));
  }
  virtual const GURL& GetURL() const OVERRIDE { return url_; }

  void MockClose(Profile* profile) {
    content::NotificationService::current()->Notify(
        chrome::NOTIFICATION_BACKGROUND_CONTENTS_CLOSED,
        content::Source<Profile>(profile),
        content::Details<BackgroundContents>(this));
    delete this;
  }

  virtual ~MockBackgroundContents() {
    content::NotificationService::current()->Notify(
        chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
        content::Source<Profile>(profile_),
        content::Details<BackgroundContents>(this));
  }

  const base::string16& appid() { return appid_; }

 private:
  GURL url_;

  // The ID of our parent application
  base::string16 appid_;

  // Parent profile
  Profile* profile_;
};

#if defined(ENABLE_NOTIFICATIONS)
// Wait for the notification created.
class NotificationWaiter : public message_center::MessageCenterObserver {
 public:
  explicit NotificationWaiter(const std::string& target_id)
      : target_id_(target_id) {}
  virtual ~NotificationWaiter() {}

  void WaitForNotificationAdded() {
    DCHECK(!run_loop_.running());
    message_center::MessageCenter* message_center =
        message_center::MessageCenter::Get();
    if (message_center->HasNotification(target_id_))
      return;

    message_center->AddObserver(this);
    run_loop_.Run();
    message_center->RemoveObserver(this);
  }

 private:
  // message_center::MessageCenterObserver overrides:
  virtual void OnNotificationAdded(
      const std::string& notification_id) OVERRIDE {
    if (notification_id == target_id_)
      run_loop_.Quit();
  }

  std::string target_id_;
  base::RunLoop run_loop_;

  DISALLOW_COPY_AND_ASSIGN(NotificationWaiter);
};

class BackgroundContentsServiceNotificationTest
    : public BrowserWithTestWindowTest {
 public:
  BackgroundContentsServiceNotificationTest() {}
  virtual ~BackgroundContentsServiceNotificationTest() {}

  // Overridden from testing::Test
  virtual void SetUp() {
    BrowserWithTestWindowTest::SetUp();
    if (!NotificationUIManager::DelegatesToMessageCenter())
      return;

    // In ChromeOS environment, BrowserWithTestWindowTest initializes
    // MessageCenter.
#if !defined(OS_CHROMEOS)
    message_center::MessageCenter::Initialize();
#endif
    profile_manager_.reset(new TestingProfileManager(
        TestingBrowserProcess::GetGlobal()));
    ASSERT_TRUE(profile_manager_->SetUp());
    MessageCenterNotificationManager* manager =
        static_cast<MessageCenterNotificationManager*>(
            g_browser_process->notification_ui_manager());
    manager->SetMessageCenterTrayDelegateForTest(
        new message_center::FakeMessageCenterTrayDelegate(
            message_center::MessageCenter::Get(), base::Closure()));
  }

  virtual void TearDown() {
    g_browser_process->notification_ui_manager()->CancelAll();
    profile_manager_.reset();
#if !defined(OS_CHROMEOS)
    message_center::MessageCenter::Shutdown();
#endif
    BrowserWithTestWindowTest::TearDown();
  }

 protected:
  // Creates crash notification for the specified extension and returns
  // the created one.
  const Notification* CreateCrashNotification(
      scoped_refptr<extensions::Extension> extension) {
    std::string notification_id =
        BackgroundContentsService::GetNotificationIdForExtensionForTesting(
            extension->id());
    NotificationWaiter waiter(notification_id);
    BackgroundContentsService::ShowBalloonForTesting(
        extension.get(), profile());
    waiter.WaitForNotificationAdded();

    return g_browser_process->notification_ui_manager()->FindById(
        notification_id);
  }

 private:
  scoped_ptr<TestingProfileManager> profile_manager_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundContentsServiceNotificationTest);
};
#endif  // ENABLE_NOTIFICATIONS

TEST_F(BackgroundContentsServiceTest, Create) {
  // Check for creation and leaks.
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
}

TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  MockBackgroundContents* contents = new MockBackgroundContents(&profile);
  EXPECT_FALSE(service.IsTracked(contents));
  contents->SendOpenedNotification(&service);
  EXPECT_TRUE(service.IsTracked(contents));
  delete contents;
  EXPECT_FALSE(service.IsTracked(contents));
}

TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAdded) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);
  GURL orig_url;
  GURL url("http://a/");
  GURL url2("http://a/");
  {
    scoped_ptr<MockBackgroundContents> contents(
        new MockBackgroundContents(&profile));
    EXPECT_EQ(0U, GetPrefs(&profile)->size());
    contents->SendOpenedNotification(&service);

    contents->Navigate(url);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
    EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));

    // Navigate the contents to a new url, should not change url.
    contents->Navigate(url2);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
    EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
  }
  // Contents are deleted, url should persist.
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
}

TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAddedAndClosed) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);

  GURL url("http://a/");
  MockBackgroundContents* contents = new MockBackgroundContents(&profile);
  EXPECT_EQ(0U, GetPrefs(&profile)->size());
  contents->SendOpenedNotification(&service);
  contents->Navigate(url);
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
  EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));

  // Fake a window closed by script.
  contents->MockClose(&profile);
  EXPECT_EQ(0U, GetPrefs(&profile)->size());
}

// Test what happens if a BackgroundContents shuts down (say, due to a renderer
// crash) then is restarted. Should not persist URL twice.
TEST_F(BackgroundContentsServiceTest, RestartBackgroundContents) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);

  GURL url("http://a/");
  {
    scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
        &profile, "appid"));
    contents->SendOpenedNotification(&service);
    contents->Navigate(url);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
    EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
  }
  // Contents deleted, url should be persisted.
  EXPECT_EQ(1U, GetPrefs(&profile)->size());

  {
    // Reopen the BackgroundContents to the same URL, we should not register the
    // URL again.
    scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
        &profile, "appid"));
    contents->SendOpenedNotification(&service);
    contents->Navigate(url);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
  }
}

// Ensures that BackgroundContentsService properly tracks the association
// between a BackgroundContents and its parent extension, including
// unregistering the BC when the extension is uninstalled.
TEST_F(BackgroundContentsServiceTest, TestApplicationIDLinkage) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);

  EXPECT_EQ(NULL,
            service.GetAppBackgroundContents(base::ASCIIToUTF16("appid")));
  MockBackgroundContents* contents = new MockBackgroundContents(&profile,
                                                                "appid");
  scoped_ptr<MockBackgroundContents> contents2(
      new MockBackgroundContents(&profile, "appid2"));
  contents->SendOpenedNotification(&service);
  EXPECT_EQ(contents, service.GetAppBackgroundContents(contents->appid()));
  contents2->SendOpenedNotification(&service);
  EXPECT_EQ(contents2.get(), service.GetAppBackgroundContents(
      contents2->appid()));
  EXPECT_EQ(0U, GetPrefs(&profile)->size());

  // Navigate the contents, then make sure the one associated with the extension
  // is unregistered.
  GURL url("http://a/");
  GURL url2("http://b/");
  contents->Navigate(url);
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
  contents2->Navigate(url2);
  EXPECT_EQ(2U, GetPrefs(&profile)->size());
  service.ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16("appid"));
  EXPECT_FALSE(service.IsTracked(contents));
  EXPECT_EQ(NULL,
            service.GetAppBackgroundContents(base::ASCIIToUTF16("appid")));
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
  EXPECT_EQ(url2.spec(), GetPrefURLForApp(&profile, contents2->appid()));
}

#if defined(ENABLE_NOTIFICATIONS)
TEST_F(BackgroundContentsServiceNotificationTest, TestShowBalloon) {
  if (!NotificationUIManager::DelegatesToMessageCenter())
    return;

  scoped_refptr<extensions::Extension> extension =
      extension_test_util::LoadManifest("image_loading_tracker", "app.json");
  ASSERT_TRUE(extension.get());
  ASSERT_TRUE(extension->GetManifestData("icons"));

  const Notification* notification = CreateCrashNotification(extension);
  EXPECT_FALSE(notification->icon().IsEmpty());
}

// Verify if a test notification can show the default extension icon for
// a crash notification for an extension without icon.
TEST_F(BackgroundContentsServiceNotificationTest, TestShowBalloonNoIcon) {
  if (!NotificationUIManager::DelegatesToMessageCenter())
    return;

  // Extension manifest file with no 'icon' field.
  scoped_refptr<extensions::Extension> extension =
      extension_test_util::LoadManifest("app", "manifest.json");
  ASSERT_TRUE(extension.get());
  ASSERT_FALSE(extension->GetManifestData("icons"));

  const Notification* notification = CreateCrashNotification(extension);
  EXPECT_FALSE(notification->icon().IsEmpty());
}
#endif
<commit_msg>Disable BackgroundContentsServiceNotificationTest for Linux-Gtk.<commit_after>// Copyright (c) 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 <string>

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/background/background_contents_service.h"
#include "chrome/browser/background/background_contents_service_factory.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/extensions/extension_test_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_browser_thread.h"
#include "extensions/common/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "url/gurl.h"

#if defined(ENABLE_NOTIFICATIONS)
#include "chrome/browser/notifications/message_center_notification_manager.h"
#include "chrome/browser/notifications/notification.h"
#include "ui/message_center/fake_message_center_tray_delegate.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_observer.h"
#endif

class BackgroundContentsServiceTest : public testing::Test {
 public:
  BackgroundContentsServiceTest() {}
  virtual ~BackgroundContentsServiceTest() {}
  virtual void SetUp() {
    command_line_.reset(new CommandLine(CommandLine::NO_PROGRAM));
  }

  const base::DictionaryValue* GetPrefs(Profile* profile) {
    return profile->GetPrefs()->GetDictionary(
        prefs::kRegisteredBackgroundContents);
  }

  // Returns the stored pref URL for the passed app id.
  std::string GetPrefURLForApp(Profile* profile, const base::string16& appid) {
    const base::DictionaryValue* pref = GetPrefs(profile);
    EXPECT_TRUE(pref->HasKey(base::UTF16ToUTF8(appid)));
    const base::DictionaryValue* value;
    pref->GetDictionaryWithoutPathExpansion(base::UTF16ToUTF8(appid), &value);
    std::string url;
    value->GetString("url", &url);
    return url;
  }

  scoped_ptr<CommandLine> command_line_;
};

class MockBackgroundContents : public BackgroundContents {
 public:
  explicit MockBackgroundContents(Profile* profile)
      : appid_(base::ASCIIToUTF16("app_id")),
        profile_(profile) {
  }
  MockBackgroundContents(Profile* profile, const std::string& id)
      : appid_(base::ASCIIToUTF16(id)),
        profile_(profile) {
  }

  void SendOpenedNotification(BackgroundContentsService* service) {
    base::string16 frame_name = base::ASCIIToUTF16("background");
    BackgroundContentsOpenedDetails details = {
        this, frame_name, appid_ };
    service->BackgroundContentsOpened(&details);
  }

  virtual void Navigate(GURL url) {
    url_ = url;
    content::NotificationService::current()->Notify(
        chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
        content::Source<Profile>(profile_),
        content::Details<BackgroundContents>(this));
  }
  virtual const GURL& GetURL() const OVERRIDE { return url_; }

  void MockClose(Profile* profile) {
    content::NotificationService::current()->Notify(
        chrome::NOTIFICATION_BACKGROUND_CONTENTS_CLOSED,
        content::Source<Profile>(profile),
        content::Details<BackgroundContents>(this));
    delete this;
  }

  virtual ~MockBackgroundContents() {
    content::NotificationService::current()->Notify(
        chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
        content::Source<Profile>(profile_),
        content::Details<BackgroundContents>(this));
  }

  const base::string16& appid() { return appid_; }

 private:
  GURL url_;

  // The ID of our parent application
  base::string16 appid_;

  // Parent profile
  Profile* profile_;
};

#if defined(ENABLE_NOTIFICATIONS) && !defined(TOOLKIT_GTK)
// Wait for the notification created.
class NotificationWaiter : public message_center::MessageCenterObserver {
 public:
  explicit NotificationWaiter(const std::string& target_id)
      : target_id_(target_id) {}
  virtual ~NotificationWaiter() {}

  void WaitForNotificationAdded() {
    DCHECK(!run_loop_.running());
    message_center::MessageCenter* message_center =
        message_center::MessageCenter::Get();
    if (message_center->HasNotification(target_id_))
      return;

    message_center->AddObserver(this);
    run_loop_.Run();
    message_center->RemoveObserver(this);
  }

 private:
  // message_center::MessageCenterObserver overrides:
  virtual void OnNotificationAdded(
      const std::string& notification_id) OVERRIDE {
    if (notification_id == target_id_)
      run_loop_.Quit();
  }

  std::string target_id_;
  base::RunLoop run_loop_;

  DISALLOW_COPY_AND_ASSIGN(NotificationWaiter);
};

class BackgroundContentsServiceNotificationTest
    : public BrowserWithTestWindowTest {
 public:
  BackgroundContentsServiceNotificationTest() {}
  virtual ~BackgroundContentsServiceNotificationTest() {}

  // Overridden from testing::Test
  virtual void SetUp() {
    BrowserWithTestWindowTest::SetUp();
    if (!NotificationUIManager::DelegatesToMessageCenter())
      return;

    // In ChromeOS environment, BrowserWithTestWindowTest initializes
    // MessageCenter.
#if !defined(OS_CHROMEOS)
    message_center::MessageCenter::Initialize();
#endif
    profile_manager_.reset(new TestingProfileManager(
        TestingBrowserProcess::GetGlobal()));
    ASSERT_TRUE(profile_manager_->SetUp());
    MessageCenterNotificationManager* manager =
        static_cast<MessageCenterNotificationManager*>(
            g_browser_process->notification_ui_manager());
    manager->SetMessageCenterTrayDelegateForTest(
        new message_center::FakeMessageCenterTrayDelegate(
            message_center::MessageCenter::Get(), base::Closure()));
  }

  virtual void TearDown() {
    g_browser_process->notification_ui_manager()->CancelAll();
    profile_manager_.reset();
#if !defined(OS_CHROMEOS)
    message_center::MessageCenter::Shutdown();
#endif
    BrowserWithTestWindowTest::TearDown();
  }

 protected:
  // Creates crash notification for the specified extension and returns
  // the created one.
  const Notification* CreateCrashNotification(
      scoped_refptr<extensions::Extension> extension) {
    std::string notification_id =
        BackgroundContentsService::GetNotificationIdForExtensionForTesting(
            extension->id());
    NotificationWaiter waiter(notification_id);
    BackgroundContentsService::ShowBalloonForTesting(
        extension.get(), profile());
    waiter.WaitForNotificationAdded();

    return g_browser_process->notification_ui_manager()->FindById(
        notification_id);
  }

 private:
  scoped_ptr<TestingProfileManager> profile_manager_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundContentsServiceNotificationTest);
};
#endif  // ENABLE_NOTIFICATIONS

TEST_F(BackgroundContentsServiceTest, Create) {
  // Check for creation and leaks.
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
}

TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  MockBackgroundContents* contents = new MockBackgroundContents(&profile);
  EXPECT_FALSE(service.IsTracked(contents));
  contents->SendOpenedNotification(&service);
  EXPECT_TRUE(service.IsTracked(contents));
  delete contents;
  EXPECT_FALSE(service.IsTracked(contents));
}

TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAdded) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);
  GURL orig_url;
  GURL url("http://a/");
  GURL url2("http://a/");
  {
    scoped_ptr<MockBackgroundContents> contents(
        new MockBackgroundContents(&profile));
    EXPECT_EQ(0U, GetPrefs(&profile)->size());
    contents->SendOpenedNotification(&service);

    contents->Navigate(url);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
    EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));

    // Navigate the contents to a new url, should not change url.
    contents->Navigate(url2);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
    EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
  }
  // Contents are deleted, url should persist.
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
}

TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAddedAndClosed) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);

  GURL url("http://a/");
  MockBackgroundContents* contents = new MockBackgroundContents(&profile);
  EXPECT_EQ(0U, GetPrefs(&profile)->size());
  contents->SendOpenedNotification(&service);
  contents->Navigate(url);
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
  EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));

  // Fake a window closed by script.
  contents->MockClose(&profile);
  EXPECT_EQ(0U, GetPrefs(&profile)->size());
}

// Test what happens if a BackgroundContents shuts down (say, due to a renderer
// crash) then is restarted. Should not persist URL twice.
TEST_F(BackgroundContentsServiceTest, RestartBackgroundContents) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);

  GURL url("http://a/");
  {
    scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
        &profile, "appid"));
    contents->SendOpenedNotification(&service);
    contents->Navigate(url);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
    EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
  }
  // Contents deleted, url should be persisted.
  EXPECT_EQ(1U, GetPrefs(&profile)->size());

  {
    // Reopen the BackgroundContents to the same URL, we should not register the
    // URL again.
    scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
        &profile, "appid"));
    contents->SendOpenedNotification(&service);
    contents->Navigate(url);
    EXPECT_EQ(1U, GetPrefs(&profile)->size());
  }
}

// Ensures that BackgroundContentsService properly tracks the association
// between a BackgroundContents and its parent extension, including
// unregistering the BC when the extension is uninstalled.
TEST_F(BackgroundContentsServiceTest, TestApplicationIDLinkage) {
  TestingProfile profile;
  BackgroundContentsService service(&profile, command_line_.get());
  BackgroundContentsServiceFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile);

  EXPECT_EQ(NULL,
            service.GetAppBackgroundContents(base::ASCIIToUTF16("appid")));
  MockBackgroundContents* contents = new MockBackgroundContents(&profile,
                                                                "appid");
  scoped_ptr<MockBackgroundContents> contents2(
      new MockBackgroundContents(&profile, "appid2"));
  contents->SendOpenedNotification(&service);
  EXPECT_EQ(contents, service.GetAppBackgroundContents(contents->appid()));
  contents2->SendOpenedNotification(&service);
  EXPECT_EQ(contents2.get(), service.GetAppBackgroundContents(
      contents2->appid()));
  EXPECT_EQ(0U, GetPrefs(&profile)->size());

  // Navigate the contents, then make sure the one associated with the extension
  // is unregistered.
  GURL url("http://a/");
  GURL url2("http://b/");
  contents->Navigate(url);
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
  contents2->Navigate(url2);
  EXPECT_EQ(2U, GetPrefs(&profile)->size());
  service.ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16("appid"));
  EXPECT_FALSE(service.IsTracked(contents));
  EXPECT_EQ(NULL,
            service.GetAppBackgroundContents(base::ASCIIToUTF16("appid")));
  EXPECT_EQ(1U, GetPrefs(&profile)->size());
  EXPECT_EQ(url2.spec(), GetPrefURLForApp(&profile, contents2->appid()));
}

#if defined(ENABLE_NOTIFICATIONS) && !defined(TOOLKIT_GTK)
TEST_F(BackgroundContentsServiceNotificationTest, TestShowBalloon) {
  if (!NotificationUIManager::DelegatesToMessageCenter())
    return;

  scoped_refptr<extensions::Extension> extension =
      extension_test_util::LoadManifest("image_loading_tracker", "app.json");
  ASSERT_TRUE(extension.get());
  ASSERT_TRUE(extension->GetManifestData("icons"));

  const Notification* notification = CreateCrashNotification(extension);
  EXPECT_FALSE(notification->icon().IsEmpty());
}

// Verify if a test notification can show the default extension icon for
// a crash notification for an extension without icon.
TEST_F(BackgroundContentsServiceNotificationTest, TestShowBalloonNoIcon) {
  if (!NotificationUIManager::DelegatesToMessageCenter())
    return;

  // Extension manifest file with no 'icon' field.
  scoped_refptr<extensions::Extension> extension =
      extension_test_util::LoadManifest("app", "manifest.json");
  ASSERT_TRUE(extension.get());
  ASSERT_FALSE(extension->GetManifestData("icons"));

  const Notification* notification = CreateCrashNotification(extension);
  EXPECT_FALSE(notification->icon().IsEmpty());
}
#endif
<|endoftext|>


<commit_before>inline
cov_mat_kth::cov_mat_kth( const std::string in_path,
			  const std::string in_actionNames,
			  const int in_scale_factor,
			  const int in_shift,
			  const int in_scene, //only for kth
			  const int in_segment_length
)
:path(in_path), actionNames(in_actionNames), scale_factor(in_scale_factor), shift(in_shift), scene(in_scene), segment_length(in_segment_length)
{
  actions.load( actionNames );
}

inline
void
cov_mat_kth::calculate( field<string> all_people, int  in_dim  )
{
  dim = in_dim;
  int n_actions = actions.n_rows;
  int n_peo =  all_people.n_rows;
  //all_people.print("people");

  for (int sc = 1; sc<=1; ++sc) //scene
  {
    for (int pe = 0; pe< n_peo; ++pe)
    {
      for (int act=0; act<n_actions; ++act)
      {

	std::stringstream load_folder;
	std::stringstream load_feat_video_i;
	std::stringstream load_labels_video_i;

	cout << "Loading.." << endl;
	load_folder << "./kth-features/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	load_feat_video_i << load_folder.str() << "/" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
	load_labels_video_i << load_folder.str() << "/lab_" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";

	//For one Video
	cov_mat_kth::one_video(load_feat_video_i.str(),	 load_labels_video_i.str() );

      }
    }
  }

}

inline
void
cov_mat_kth::one_video( std::string load_feat_video_i,	std::string load_labels_video_i )
{
  mat mat_features_video_i;
  vec lab_video_i;

  mat_features_video_i.load( load_feat_video_i, raw_ascii );
  lab_video_i.load( load_labels_video_i, raw_ascii );
  int n_vec = lab_video_i.n_elem;
  int last = lab_video_i( n_vec - 1 );

  for (int l=2; l<last-segment_length; l = l+4 )
  {
    running_stat_vec<rowvec> stat_seg(true);
    int k =0;

    for (int j=l; j<segment_length; ++j)
    {
      k++;
      uvec indices = find(lab_video_i == j);
      mat tmp_feat = mat_features_video_i.elem(indices);
      for (v=0; v < tmp_feat.n_cols; ++v)
      {
	vec sample = tmp_feat.col(v);
	stat_seg (sample);

      }

    }

   cout << "k= " << k << endl;
   getchar();

  }

}

/*
running_stat_vec<rowvec> more_stats(true);

for(uword i=0; i<20; ++i)
  {
  sample = randu<rowvec>(3);

  sample(1) -= sample(0);
  sample(2) += sample(1);

  more_stats(sample);
  }*/<commit_msg>First try<commit_after>inline
cov_mat_kth::cov_mat_kth( const std::string in_path,
			  const std::string in_actionNames,
			  const int in_scale_factor,
			  const int in_shift,
			  const int in_scene, //only for kth
			  const int in_segment_length
)
:path(in_path), actionNames(in_actionNames), scale_factor(in_scale_factor), shift(in_shift), scene(in_scene), segment_length(in_segment_length)
{
  actions.load( actionNames );
}

inline
void
cov_mat_kth::calculate( field<string> all_people, int  in_dim  )
{
  dim = in_dim;
  int n_actions = actions.n_rows;
  int n_peo =  all_people.n_rows;
  //all_people.print("people");

  for (int sc = 1; sc<=1; ++sc) //scene
  {
    for (int pe = 0; pe< n_peo; ++pe)
    {
      for (int act=0; act<n_actions; ++act)
      {

	std::stringstream load_folder;
	std::stringstream load_feat_video_i;
	std::stringstream load_labels_video_i;

	cout << "Loading.." << endl;
	load_folder << "./kth-features/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	load_feat_video_i << load_folder.str() << "/" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
	load_labels_video_i << load_folder.str() << "/lab_" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";

	//For one Video
	cov_mat_kth::one_video(load_feat_video_i.str(),	 load_labels_video_i.str() );

      }
    }
  }

}

inline
void
cov_mat_kth::one_video( std::string load_feat_video_i,	std::string load_labels_video_i )
{
  mat mat_features_video_i;
  vec lab_video_i;

  mat_features_video_i.load( load_feat_video_i, raw_ascii );
  lab_video_i.load( load_labels_video_i, raw_ascii );
  int n_vec = lab_video_i.n_elem;
  int last = lab_video_i( n_vec - 1 );

  for (int l=2; l<last-segment_length; l = l+4 )
  {
    running_stat_vec<rowvec> stat_seg(true);
    int k =0;

    for (int j=l; j<segment_length; ++j)
    {
      k++;
      uvec indices = find(lab_video_i == j);
      mat tmp_feat = mat_features_video_i.elem(indices);
      for (int v=0; v < tmp_feat.n_cols; ++v)
      {
	vec sample = tmp_feat.col(v);
	stat_seg (sample);

      }

    }

   cout << "k= " << k << endl;
   getchar();

  }

}

/*
running_stat_vec<rowvec> more_stats(true);

for(uword i=0; i<20; ++i)
  {
  sample = randu<rowvec>(3);

  sample(1) -= sample(0);
  sample(2) += sample(1);

  more_stats(sample);
  }*/<|endoftext|>


<commit_before>inline
cov_mat_kth::cov_mat_kth( const std::string in_path,
			  const std::string in_actionNames,
			  const int in_scale_factor,
			  const int in_shift,
			  const int in_scene, //only for kth
			  const int in_segment_length
)
:path(in_path), actionNames(in_actionNames), scale_factor(in_scale_factor), shift(in_shift), scene(in_scene), segment_length(in_segment_length)
{
  actions.load( actionNames );
}

inline
void
cov_mat_kth::calculate( field<string> in_all_people, int  in_dim  )
{
  all_people = in_all_people;
  dim = in_dim;
  int n_actions = actions.n_rows;
  int n_peo =  all_people.n_rows;
  //all_people.print("people");

  for (int sc = 1; sc<=1; ++sc) //scene
  {
    for (int pe = 0; pe< n_peo; ++pe)
    {
      for (int act=0; act<n_actions; ++act)
      {

	std::stringstream load_folder;
	std::stringstream load_feat_video_i;
	std::stringstream load_labels_video_i;

	//cout << "Loading.." << endl;
	load_folder << path << "/kth-features/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	load_feat_video_i << load_folder.str() << "/" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";
	load_labels_video_i << load_folder.str() << "/lab_" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	//For one Video
	cov_mat_kth::one_video(load_feat_video_i.str(),	 load_labels_video_i.str(), sc, pe, act );
	//getchar();

      }
    }
  }
}

inline
void
cov_mat_kth::one_video( std::string load_feat_video_i,	std::string load_labels_video_i, int sc, int pe, int act )
{
  cout << load_feat_video_i << endl;
  mat mat_features_video_i;
  vec lab_video_i;

  mat_features_video_i.load( load_feat_video_i, hdf5_binary );
  lab_video_i.load( load_labels_video_i, hdf5_binary );
  int n_vec = lab_video_i.n_elem;
  int last = lab_video_i( n_vec - 1 );
  cout << last << endl;

  int s = 0;

  std::stringstream save_folder;
  save_folder << "./kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;

  for (int l=2; l<last-segment_length; l = l+4 )
  {
    running_stat_vec<rowvec> stat_seg(true);
    //int k =0;

    //cout << " " << l;

    for (int j=l; j<=segment_length+1; ++j)
    {
      //k++;
      cout << " " << j;
      uvec indices = find(lab_video_i == j);
      mat tmp_feat = mat_features_video_i.cols(indices);
      //cout << "row&col " << tmp_feat.n_rows << " & " << tmp_feat.n_cols << endl;
      for (int v=0; v < tmp_feat.n_cols; ++v)
      {
	vec sample = tmp_feat.col(v);
	stat_seg (sample);

      }

    }

    cout << " " << stat_seg.count();
    std::stringstream save_cov_seg;
    save_cov_seg << save_folder.str() << "/cov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

    double THRESH = 0.000001;
    mat cov_seg_i = stat_seg.cov();

    //Following Mehrtash suggestions as per email dated June26th 2014
    cov_seg_i = 0.5*(cov_seg_i + cov_seg_i.t());
    vec D;
    mat V;
    eig_sym(D, V, cov_seg_i);
    uvec q1 = find(D < THRESH);

    if (q1.n_elem>0)
    {
      for (uword pos = 0; pos < q1.n_elem; ++pos)
      {
	D( q1(pos) ) = THRESH;

      }

      cov_seg_i = V*diagmat(D)*V.t();

    }

    //end suggestion

    cov_seg_i.save( save_cov_seg.str(), hdf5_binary );

    s++;

  }

  std::stringstream save_seg;
  vec total_seg;
  total_seg.zeros(1);
  total_seg( 0 ) = s;
  save_seg << save_folder.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
  total_seg.save( save_seg.str(), raw_ascii );
 cout << "press a key " ;
  getchar();

}

<commit_msg>Another bug buuuuuu :( <commit_after>inline
cov_mat_kth::cov_mat_kth( const std::string in_path,
			  const std::string in_actionNames,
			  const int in_scale_factor,
			  const int in_shift,
			  const int in_scene, //only for kth
			  const int in_segment_length
)
:path(in_path), actionNames(in_actionNames), scale_factor(in_scale_factor), shift(in_shift), scene(in_scene), segment_length(in_segment_length)
{
  actions.load( actionNames );
}

inline
void
cov_mat_kth::calculate( field<string> in_all_people, int  in_dim  )
{
  all_people = in_all_people;
  dim = in_dim;
  int n_actions = actions.n_rows;
  int n_peo =  all_people.n_rows;
  //all_people.print("people");

  for (int sc = 1; sc<=1; ++sc) //scene
  {
    for (int pe = 0; pe< n_peo; ++pe)
    {
      for (int act=0; act<n_actions; ++act)
      {

	std::stringstream load_folder;
	std::stringstream load_feat_video_i;
	std::stringstream load_labels_video_i;

	//cout << "Loading.." << endl;
	load_folder << path << "/kth-features/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	load_feat_video_i << load_folder.str() << "/" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";
	load_labels_video_i << load_folder.str() << "/lab_" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	//For one Video
	cov_mat_kth::one_video(load_feat_video_i.str(),	 load_labels_video_i.str(), sc, pe, act );
	//getchar();

      }
    }
  }
}

inline
void
cov_mat_kth::one_video( std::string load_feat_video_i,	std::string load_labels_video_i, int sc, int pe, int act )
{
  cout << load_feat_video_i << endl;
  mat mat_features_video_i;
  vec lab_video_i;

  mat_features_video_i.load( load_feat_video_i, hdf5_binary );
  lab_video_i.load( load_labels_video_i, hdf5_binary );
  int n_vec = lab_video_i.n_elem;
  int last = lab_video_i( n_vec - 1 );
  cout << last << endl;

  int s = 0;

  std::stringstream save_folder;
  save_folder << "./kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;

  for (int l=2; l<last-segment_length; l = l+4 )
  {
    running_stat_vec<rowvec> stat_seg(true);
    //int k =0;

    //cout << " " << l;

    for (int j=l; j<=segment_length+1; ++j)
    {
      //k++;
      cout << " " << j;
      uvec indices = find(lab_video_i == j);
      mat tmp_feat = mat_features_video_i.cols(indices);
      //cout << "row&col " << tmp_feat.n_rows << " & " << tmp_feat.n_cols << endl;
      for (int v=0; v < tmp_feat.n_cols; ++v)
      {
	vec sample = tmp_feat.col(v);
	stat_seg (sample);

      }

    }

    cout << endl;
    cout << " " << stat_seg.count();
    std::stringstream save_cov_seg;
    save_cov_seg << save_folder.str() << "/cov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

    double THRESH = 0.000001;
    mat cov_seg_i = stat_seg.cov();

    //Following Mehrtash suggestions as per email dated June26th 2014
    cov_seg_i = 0.5*(cov_seg_i + cov_seg_i.t());
    vec D;
    mat V;
    eig_sym(D, V, cov_seg_i);
    uvec q1 = find(D < THRESH);

    if (q1.n_elem>0)
    {
      for (uword pos = 0; pos < q1.n_elem; ++pos)
      {
	D( q1(pos) ) = THRESH;

      }

      cov_seg_i = V*diagmat(D)*V.t();

    }

    //end suggestion

    cov_seg_i.save( save_cov_seg.str(), hdf5_binary );

    s++;

  }

  std::stringstream save_seg;
  vec total_seg;
  total_seg.zeros(1);
  total_seg( 0 ) = s;
  save_seg << save_folder.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
  total_seg.save( save_seg.str(), raw_ascii );
 cout << "press a key " ;
  getchar();

}

<|endoftext|>


<commit_before>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_REGION_HPP
#define TOML11_REGION_HPP
#include "exception.hpp"
#include <memory>
#include <vector>
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <iomanip>
#include <cassert>

namespace toml
{
namespace detail
{

// helper function to avoid std::string(0, 'c') or std::string(iter, iter)
template<typename Iterator>
std::string make_string(Iterator first, Iterator last)
{
    if(first == last) {return "";}
    return std::string(first, last);
}
inline std::string make_string(std::size_t len, char c)
{
    if(len == 0) {return "";}
    return std::string(len, c);
}

// region_base is a base class of location and region that are defined below.
// it will be used to generate better error messages.
struct region_base
{
    region_base() = default;
    virtual ~region_base() = default;
    region_base(const region_base&) = default;
    region_base(region_base&&     ) = default;
    region_base& operator=(const region_base&) = default;
    region_base& operator=(region_base&&     ) = default;

    virtual bool is_ok()           const noexcept {return false;}

    virtual std::string str()      const {return std::string("unknown region");}
    virtual std::string name()     const {return std::string("unknown file");}
    virtual std::string line()     const {return std::string("unknown line");}
    virtual std::string line_num() const {return std::string("?");}

    // length of the region
    virtual std::size_t size()     const noexcept {return 0;}
    // number of characters in the line before the region
    virtual std::size_t before()   const noexcept {return 0;}
    // number of characters in the line after the region
    virtual std::size_t after()    const noexcept {return 0;}

    virtual std::string comment_before() const {return "";} // just before
    virtual std::string comment_inline() const {return "";} // in the same line
    virtual std::string comment()        const {return "";} // concatenate
    // ```toml
    // # comment_before
    // key = "value" # comment_inline
    // ```
};

// location represents a position in a container, which contains a file content.
// it can be considered as a region that contains only one character.
//
// it contains pointer to the file content and iterator that points the current
// location.
template<typename Container>
struct location final : public region_base
{
    using const_iterator = typename Container::const_iterator;
    using source_ptr     = std::shared_ptr<const Container>;

    static_assert(std::is_same<char, typename Container::value_type>::value,"");
    static_assert(std::is_same<std::random_access_iterator_tag,
        typename std::iterator_traits<const_iterator>::iterator_category>::value,
        "container should be randomly accessible");

    location(std::string name, Container cont)
      : source_(std::make_shared<Container>(std::move(cont))), line_number_(1),
        source_name_(std::move(name)), iter_(source_->cbegin())
    {}
    location(const location&) = default;
    location(location&&)      = default;
    location& operator=(const location&) = default;
    location& operator=(location&&)      = default;
    ~location() = default;

    bool is_ok() const noexcept override {return static_cast<bool>(source_);}

    // this const prohibits codes like `++(loc.iter())`.
    const const_iterator iter()  const noexcept {return iter_;}

    const_iterator begin() const noexcept {return source_->cbegin();}
    const_iterator end()   const noexcept {return source_->cend();}

    // XXX `location::line_num()` used to be implemented using `std::count` to
    // count a number of '\n'. But with a long toml file (typically, 10k lines),
    // it becomes intolerably slow because each time it generates error messages,
    // it counts '\n' from thousands of characters. To workaround it, I decided
    // to introduce `location::line_number_` member variable and synchronize it
    // to the location changes the point to look. So an overload of `iter()`
    // which returns mutable reference is removed and `advance()`, `retrace()`
    // and `reset()` is added.
    void advance(std::size_t n = 1) noexcept
    {
        this->line_number_ += std::count(this->iter_, this->iter_ + n, '\n');
        this->iter_ += n;
        return;
    }
    void retrace(std::size_t n = 1) noexcept
    {
        this->line_number_ -= std::count(this->iter_ - n, this->iter_, '\n');
        this->iter_ -= n;
        return;
    }
    void reset(const_iterator rollback) noexcept
    {
        // since c++11, std::distance works in both ways for random-access
        // iterators and returns a negative value if `first > last`.
        if(0 <= std::distance(rollback, this->iter_)) // rollback < iter
        {
            this->line_number_ -= std::count(rollback, this->iter_, '\n');
        }
        else // iter < rollback [[unlikely]]
        {
            this->line_number_ += std::count(this->iter_, rollback, '\n');
        }
        this->iter_ = rollback;
        return;
    }

    std::string str()  const override {return make_string(1, *this->iter());}
    std::string name() const override {return source_name_;}

    std::string line_num() const override
    {
        return std::to_string(this->line_number_);
    }

    std::string line() const override
    {
        return make_string(this->line_begin(), this->line_end());
    }

    const_iterator line_begin() const noexcept
    {
        using reverse_iterator = std::reverse_iterator<const_iterator>;
        return std::find(reverse_iterator(this->iter()),
                         reverse_iterator(this->begin()), '\n').base();
    }
    const_iterator line_end() const noexcept
    {
        return std::find(this->iter(), this->end(), '\n');
    }

    // location is always points a character. so the size is 1.
    std::size_t size() const noexcept override
    {
        return 1u;
    }
    std::size_t before() const noexcept override
    {
        return std::distance(this->line_begin(), this->iter());
    }
    std::size_t after() const noexcept override
    {
        return std::distance(this->iter(), this->line_end());
    }

    source_ptr const& source() const& noexcept {return source_;}
    source_ptr&&      source() &&     noexcept {return std::move(source_);}

  private:

    source_ptr     source_;
    std::size_t    line_number_;
    std::string    source_name_;
    const_iterator iter_;
};

// region represents a range in a container, which contains a file content.
//
// it contains pointer to the file content and iterator that points the first
// and last location.
template<typename Container>
struct region final : public region_base
{
    using const_iterator = typename Container::const_iterator;
    using source_ptr     = std::shared_ptr<const Container>;

    static_assert(std::is_same<char, typename Container::value_type>::value,"");
    static_assert(std::is_same<std::random_access_iterator_tag,
        typename std::iterator_traits<const_iterator>::iterator_category>::value,
        "container should be randomly accessible");

    // delete default constructor. source_ never be null.
    region() = delete;

    region(const location<Container>& loc)
      : source_(loc.source()), source_name_(loc.name()),
        first_(loc.iter()), last_(loc.iter())
    {}
    region(location<Container>&& loc)
      : source_(loc.source()), source_name_(loc.name()),
        first_(loc.iter()), last_(loc.iter())
    {}

    region(const location<Container>& loc, const_iterator f, const_iterator l)
      : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
    {}
    region(location<Container>&& loc, const_iterator f, const_iterator l)
      : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
    {}

    region(const region&) = default;
    region(region&&)      = default;
    region& operator=(const region&) = default;
    region& operator=(region&&)      = default;
    ~region() = default;

    region& operator+=(const region& other)
    {
        if(this->begin() != other.begin() || this->end() != other.end() ||
           this->last_  != other.first_)
        {
            throw internal_error("invalid region concatenation");
        }
        this->last_ = other.last_;
        return *this;
    }

    bool is_ok() const noexcept override {return static_cast<bool>(source_);}

    std::string str()  const override {return make_string(first_, last_);}
    std::string line() const override
    {
        if(this->contain_newline())
        {
            return make_string(this->line_begin(),
                    std::find(this->line_begin(), this->last(), '\n'));
        }
        return make_string(this->line_begin(), this->line_end());
    }
    std::string line_num() const override
    {
        return std::to_string(1 + std::count(this->begin(), this->first(), '\n'));
    }

    std::size_t size() const noexcept override
    {
        return std::distance(first_, last_);
    }
    std::size_t before() const noexcept override
    {
        return std::distance(this->line_begin(), this->first());
    }
    std::size_t after() const noexcept override
    {
        return std::distance(this->last(), this->line_end());
    }

    bool contain_newline() const noexcept
    {
        return std::find(this->first(), this->last(), '\n') != this->last();
    }

    const_iterator line_begin() const noexcept
    {
        using reverse_iterator = std::reverse_iterator<const_iterator>;
        return std::find(reverse_iterator(this->first()),
                         reverse_iterator(this->begin()), '\n').base();
    }
    const_iterator line_end() const noexcept
    {
        return std::find(this->last(), this->end(), '\n');
    }

    const_iterator begin() const noexcept {return source_->cbegin();}
    const_iterator end()   const noexcept {return source_->cend();}
    const_iterator first() const noexcept {return first_;}
    const_iterator last()  const noexcept {return last_;}

    source_ptr const& source() const& noexcept {return source_;}
    source_ptr&&      source() &&     noexcept {return std::move(source_);}

    std::string name() const override {return source_name_;}

    std::string comment_before() const override
    {
        auto iter = this->line_begin(); // points the first element
        std::vector<std::pair<decltype(iter), decltype(iter)>> comments;
        while(iter != this->begin())
        {
            iter = std::prev(iter);
            using rev_iter = std::reverse_iterator<decltype(iter)>;
            auto line_before = std::find(rev_iter(iter), rev_iter(this->begin()),
                                         '\n').base();
            // range [line_before, iter) represents the previous line

            auto comment_found = std::find(line_before, iter, '#');
            if(iter != comment_found && std::all_of(line_before, comment_found,
                    [](const char c) noexcept -> bool {
                        return c == ' ' || c == '\t';
                    }))
            {
                // the line before this range contains only a comment.
                comments.push_back(std::make_pair(comment_found, iter));
            }
            else
            {
                break;
            }
            iter = line_before;
        }

        std::string com;
        for(auto i = comments.crbegin(), e = comments.crend(); i!=e; ++i)
        {
            if(i != comments.crbegin()) {com += '\n';}
            com += std::string(i->first, i->second);
        }
        return com;
    }

    std::string comment_inline() const override
    {
        if(this->contain_newline())
        {
            std::string com;
            // check both the first and the last line.
            const auto first_line_end =
                std::find(this->line_begin(), this->last(), '\n');
            const auto first_comment_found =
                std::find(this->line_begin(), first_line_end, '#');

            if(first_comment_found != first_line_end)
            {
                com += std::string(first_comment_found, first_line_end);
            }

            const auto last_comment_found =
                std::find(this->last(), this->line_end(), '#');
            if(last_comment_found != this->line_end())
            {
                if(!com.empty()){com += '\n';}
                com += std::string(last_comment_found, this->line_end());
            }
            return com;
        }
        const auto comment_found =
            std::find(this->line_begin(), this->line_end(), '#');
        return std::string(comment_found, this->line_end());
    }

    std::string comment() const override
    {
        std::string com_bef = this->comment_before();
        std::string com_inl = this->comment_inline();
        if(!com_bef.empty() && !com_inl.empty())
        {
            com_bef += '\n';
            return com_bef + com_inl;
        }
        else if(com_bef.empty())
        {
            return com_inl;
        }
        else
        {
            return com_bef;
        }
    }

  private:

    source_ptr     source_;
    std::string    source_name_;
    const_iterator first_, last_;
};

// to show a better error message.
inline std::string format_underline(const std::string& message,
        const std::vector<std::pair<region_base const*, std::string>>& reg_com,
        const std::vector<std::string>& helps = {})
{
    assert(!reg_com.empty());

    const auto line_num_width = std::max_element(reg_com.begin(), reg_com.end(),
        [](std::pair<region_base const*, std::string> const& lhs,
           std::pair<region_base const*, std::string> const& rhs)
        {
            return lhs.first->line_num().size() < rhs.first->line_num().size();
        }
    )->first->line_num().size();

    std::ostringstream retval;
    retval << message << '\n';

    for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter)
    {
        // if the filenames are the same, print "..."
        if(iter != reg_com.begin() &&
           std::prev(iter)->first->name() == iter->first->name())
        {
            retval << "\n ...\n";
        }
        else // if filename differs, print " --> filename.toml"
        {
            if(iter != reg_com.begin()) {retval << '\n';}
            retval << " --> " << iter->first->name() << '\n';
        }
        const region_base* const reg = iter->first;
        const std::string&   comment = iter->second;

        retval << ' ' << std::setw(line_num_width) << reg->line_num();
        retval << " | " << reg->line() << '\n';
        retval << make_string(line_num_width + 1, ' ');
        retval << " | " << make_string(reg->before(), ' ');

        if(reg->size() == 1)
        {
            // invalid
            // ^------
            retval << '^';
            retval << make_string(reg->after(), '-');
        }
        else
        {
            // invalid
            // ~~~~~~~
            const auto underline_len = std::min(reg->size(), reg->line().size());
            retval << make_string(underline_len, '~');
        }
        retval << ' ';
        retval << comment;
    }

    if(!helps.empty())
    {
        retval << '\n';
        retval << make_string(line_num_width + 1, ' ');
        retval << " | ";
        for(const auto help : helps)
        {
            retval << "\nHint: ";
            retval << help;
        }
    }
    return retval.str();
}

} // detail
} // toml
#endif// TOML11_REGION_H
<commit_msg>feat: :boom: change comment interface in region<commit_after>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_REGION_HPP
#define TOML11_REGION_HPP
#include "exception.hpp"
#include <memory>
#include <vector>
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <iomanip>
#include <cassert>

namespace toml
{
namespace detail
{

// helper function to avoid std::string(0, 'c') or std::string(iter, iter)
template<typename Iterator>
std::string make_string(Iterator first, Iterator last)
{
    if(first == last) {return "";}
    return std::string(first, last);
}
inline std::string make_string(std::size_t len, char c)
{
    if(len == 0) {return "";}
    return std::string(len, c);
}

// region_base is a base class of location and region that are defined below.
// it will be used to generate better error messages.
struct region_base
{
    region_base() = default;
    virtual ~region_base() = default;
    region_base(const region_base&) = default;
    region_base(region_base&&     ) = default;
    region_base& operator=(const region_base&) = default;
    region_base& operator=(region_base&&     ) = default;

    virtual bool is_ok()           const noexcept {return false;}

    virtual std::string str()      const {return std::string("unknown region");}
    virtual std::string name()     const {return std::string("unknown file");}
    virtual std::string line()     const {return std::string("unknown line");}
    virtual std::string line_num() const {return std::string("?");}

    // length of the region
    virtual std::size_t size()     const noexcept {return 0;}
    // number of characters in the line before the region
    virtual std::size_t before()   const noexcept {return 0;}
    // number of characters in the line after the region
    virtual std::size_t after()    const noexcept {return 0;}

    virtual std::vector<std::string> comments()const {return {};}
    // ```toml
    // # comment_before
    // key = "value" # comment_inline
    // ```
};

// location represents a position in a container, which contains a file content.
// it can be considered as a region that contains only one character.
//
// it contains pointer to the file content and iterator that points the current
// location.
template<typename Container>
struct location final : public region_base
{
    using const_iterator = typename Container::const_iterator;
    using source_ptr     = std::shared_ptr<const Container>;

    static_assert(std::is_same<char, typename Container::value_type>::value,"");
    static_assert(std::is_same<std::random_access_iterator_tag,
        typename std::iterator_traits<const_iterator>::iterator_category>::value,
        "container should be randomly accessible");

    location(std::string name, Container cont)
      : source_(std::make_shared<Container>(std::move(cont))), line_number_(1),
        source_name_(std::move(name)), iter_(source_->cbegin())
    {}
    location(const location&) = default;
    location(location&&)      = default;
    location& operator=(const location&) = default;
    location& operator=(location&&)      = default;
    ~location() = default;

    bool is_ok() const noexcept override {return static_cast<bool>(source_);}

    // this const prohibits codes like `++(loc.iter())`.
    const const_iterator iter()  const noexcept {return iter_;}

    const_iterator begin() const noexcept {return source_->cbegin();}
    const_iterator end()   const noexcept {return source_->cend();}

    // XXX `location::line_num()` used to be implemented using `std::count` to
    // count a number of '\n'. But with a long toml file (typically, 10k lines),
    // it becomes intolerably slow because each time it generates error messages,
    // it counts '\n' from thousands of characters. To workaround it, I decided
    // to introduce `location::line_number_` member variable and synchronize it
    // to the location changes the point to look. So an overload of `iter()`
    // which returns mutable reference is removed and `advance()`, `retrace()`
    // and `reset()` is added.
    void advance(std::size_t n = 1) noexcept
    {
        this->line_number_ += std::count(this->iter_, this->iter_ + n, '\n');
        this->iter_ += n;
        return;
    }
    void retrace(std::size_t n = 1) noexcept
    {
        this->line_number_ -= std::count(this->iter_ - n, this->iter_, '\n');
        this->iter_ -= n;
        return;
    }
    void reset(const_iterator rollback) noexcept
    {
        // since c++11, std::distance works in both ways for random-access
        // iterators and returns a negative value if `first > last`.
        if(0 <= std::distance(rollback, this->iter_)) // rollback < iter
        {
            this->line_number_ -= std::count(rollback, this->iter_, '\n');
        }
        else // iter < rollback [[unlikely]]
        {
            this->line_number_ += std::count(this->iter_, rollback, '\n');
        }
        this->iter_ = rollback;
        return;
    }

    std::string str()  const override {return make_string(1, *this->iter());}
    std::string name() const override {return source_name_;}

    std::string line_num() const override
    {
        return std::to_string(this->line_number_);
    }

    std::string line() const override
    {
        return make_string(this->line_begin(), this->line_end());
    }

    const_iterator line_begin() const noexcept
    {
        using reverse_iterator = std::reverse_iterator<const_iterator>;
        return std::find(reverse_iterator(this->iter()),
                         reverse_iterator(this->begin()), '\n').base();
    }
    const_iterator line_end() const noexcept
    {
        return std::find(this->iter(), this->end(), '\n');
    }

    // location is always points a character. so the size is 1.
    std::size_t size() const noexcept override
    {
        return 1u;
    }
    std::size_t before() const noexcept override
    {
        return std::distance(this->line_begin(), this->iter());
    }
    std::size_t after() const noexcept override
    {
        return std::distance(this->iter(), this->line_end());
    }

    source_ptr const& source() const& noexcept {return source_;}
    source_ptr&&      source() &&     noexcept {return std::move(source_);}

  private:

    source_ptr     source_;
    std::size_t    line_number_;
    std::string    source_name_;
    const_iterator iter_;
};

// region represents a range in a container, which contains a file content.
//
// it contains pointer to the file content and iterator that points the first
// and last location.
template<typename Container>
struct region final : public region_base
{
    using const_iterator = typename Container::const_iterator;
    using source_ptr     = std::shared_ptr<const Container>;

    static_assert(std::is_same<char, typename Container::value_type>::value,"");
    static_assert(std::is_same<std::random_access_iterator_tag,
        typename std::iterator_traits<const_iterator>::iterator_category>::value,
        "container should be randomly accessible");

    // delete default constructor. source_ never be null.
    region() = delete;

    region(const location<Container>& loc)
      : source_(loc.source()), source_name_(loc.name()),
        first_(loc.iter()), last_(loc.iter())
    {}
    region(location<Container>&& loc)
      : source_(loc.source()), source_name_(loc.name()),
        first_(loc.iter()), last_(loc.iter())
    {}

    region(const location<Container>& loc, const_iterator f, const_iterator l)
      : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
    {}
    region(location<Container>&& loc, const_iterator f, const_iterator l)
      : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
    {}

    region(const region&) = default;
    region(region&&)      = default;
    region& operator=(const region&) = default;
    region& operator=(region&&)      = default;
    ~region() = default;

    region& operator+=(const region& other)
    {
        if(this->begin() != other.begin() || this->end() != other.end() ||
           this->last_  != other.first_)
        {
            throw internal_error("invalid region concatenation");
        }
        this->last_ = other.last_;
        return *this;
    }

    bool is_ok() const noexcept override {return static_cast<bool>(source_);}

    std::string str()  const override {return make_string(first_, last_);}
    std::string line() const override
    {
        if(this->contain_newline())
        {
            return make_string(this->line_begin(),
                    std::find(this->line_begin(), this->last(), '\n'));
        }
        return make_string(this->line_begin(), this->line_end());
    }
    std::string line_num() const override
    {
        return std::to_string(1 + std::count(this->begin(), this->first(), '\n'));
    }

    std::size_t size() const noexcept override
    {
        return std::distance(first_, last_);
    }
    std::size_t before() const noexcept override
    {
        return std::distance(this->line_begin(), this->first());
    }
    std::size_t after() const noexcept override
    {
        return std::distance(this->last(), this->line_end());
    }

    bool contain_newline() const noexcept
    {
        return std::find(this->first(), this->last(), '\n') != this->last();
    }

    const_iterator line_begin() const noexcept
    {
        using reverse_iterator = std::reverse_iterator<const_iterator>;
        return std::find(reverse_iterator(this->first()),
                         reverse_iterator(this->begin()), '\n').base();
    }
    const_iterator line_end() const noexcept
    {
        return std::find(this->last(), this->end(), '\n');
    }

    const_iterator begin() const noexcept {return source_->cbegin();}
    const_iterator end()   const noexcept {return source_->cend();}
    const_iterator first() const noexcept {return first_;}
    const_iterator last()  const noexcept {return last_;}

    source_ptr const& source() const& noexcept {return source_;}
    source_ptr&&      source() &&     noexcept {return std::move(source_);}

    std::string name() const override {return source_name_;}

    std::vector<std::string> comments() const override
    {
        // assuming the current region (`*this`) points a value.
        // ```toml
        // a = "value"
        //     ^^^^^^^- this region
        // ```
        using rev_iter = std::reverse_iterator<const_iterator>;

        std::vector<std::string> com{};
        {
            // find comments just before the current region.
            // ```toml
            // # this should be collected.
            // # this also.
            // a = value # not this.
            // ```
            auto iter = this->line_begin(); // points the first character
            while(iter != this->begin())
            {
                iter = std::prev(iter);

                // range [line_start, iter) represents the previous line
                const auto line_start   = std::find(
                        rev_iter(iter), rev_iter(this->begin()), '\n').base();
                const auto comment_found = std::find(line_start, iter, '#');
                if(comment_found == iter)
                {
                    break; // comment not found.
                }

                // exclude the following case.
                // > a = "foo" # comment // <-- this is not a comment for b but a.
                // > b = "current value"
                if(std::all_of(line_start, comment_found,
                        [](const char c) noexcept -> bool {
                            return c == ' ' || c == '\t';
                        }))
                {
                    // unwrap the first '#' by std::next.
                    com.push_back(make_string(std::next(comment_found), iter));
                }
                else
                {
                    break;
                }
                iter = line_start;
            }
        }
        {
            // find comments just after the current region.
            // ```toml
            // # not this.
            // a = value # this one.
            // a = [ # not this (technically difficult)
            //
            // ] # and this.
            // ```
            // The reason why it's difficult is that it requires parsing in the
            // following case.
            // ```toml
            // a = [ 10 # this comment is for `10`. not for `a` but `a[0]`.
            // # ...
            // ] # this is apparently a comment for a.
            //
            // b = [
            // 3.14 ] # there is no way to add a comment to `3.14` currently.
            //
            // c = [
            //   3.14 # do this if you need a comment here.
            // ]
            // ```
            const auto last_comment_found =
                std::find(this->last(), this->line_end(), '#');
            if(last_comment_found != this->line_end()) // '#' found
            {
                com.push_back(make_string(last_comment_found, this->line_end()));
            }
        }
        return com;
    }

  private:

    source_ptr     source_;
    std::string    source_name_;
    const_iterator first_, last_;
};

// to show a better error message.
inline std::string format_underline(const std::string& message,
        const std::vector<std::pair<region_base const*, std::string>>& reg_com,
        const std::vector<std::string>& helps = {})
{
    assert(!reg_com.empty());

    const auto line_num_width = std::max_element(reg_com.begin(), reg_com.end(),
        [](std::pair<region_base const*, std::string> const& lhs,
           std::pair<region_base const*, std::string> const& rhs)
        {
            return lhs.first->line_num().size() < rhs.first->line_num().size();
        }
    )->first->line_num().size();

    std::ostringstream retval;
    retval << message << '\n';

    for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter)
    {
        // if the filenames are the same, print "..."
        if(iter != reg_com.begin() &&
           std::prev(iter)->first->name() == iter->first->name())
        {
            retval << "\n ...\n";
        }
        else // if filename differs, print " --> filename.toml"
        {
            if(iter != reg_com.begin()) {retval << '\n';}
            retval << " --> " << iter->first->name() << '\n';
        }
        const region_base* const reg = iter->first;
        const std::string&   comment = iter->second;

        retval << ' ' << std::setw(line_num_width) << reg->line_num();
        retval << " | " << reg->line() << '\n';
        retval << make_string(line_num_width + 1, ' ');
        retval << " | " << make_string(reg->before(), ' ');

        if(reg->size() == 1)
        {
            // invalid
            // ^------
            retval << '^';
            retval << make_string(reg->after(), '-');
        }
        else
        {
            // invalid
            // ~~~~~~~
            const auto underline_len = std::min(reg->size(), reg->line().size());
            retval << make_string(underline_len, '~');
        }
        retval << ' ';
        retval << comment;
    }

    if(!helps.empty())
    {
        retval << '\n';
        retval << make_string(line_num_width + 1, ' ');
        retval << " | ";
        for(const auto help : helps)
        {
            retval << "\nHint: ";
            retval << help;
        }
    }
    return retval.str();
}

} // detail
} // toml
#endif// TOML11_REGION_H
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of default digitization module
 * @copyright MIT License
 */

#include "DefaultDigitizerModule.hpp"

#include "core/utils/unit.h"
#include "tools/ROOT.h"

#include <TFile.h>
#include <TH1D.h>
#include <TProfile.h>

#include "objects/PixelHit.hpp"

using namespace allpix;

DefaultDigitizerModule::DefaultDigitizerModule(Configuration config,
                                               Messenger* messenger,
                                               std::shared_ptr<Detector> detector)
    : Module(config, std::move(detector)), config_(std::move(config)), messenger_(messenger), pixel_message_(nullptr) {
    // Enable parallelization of this module if multithreading is enabled
    enable_parallelization();

    // Require PixelCharge message for single detector
    messenger_->bindSingle(this, &DefaultDigitizerModule::pixel_message_, MsgFlags::REQUIRED);

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

    // Set defaults for config variables
    config_.setDefault<int>("electronics_noise", Units::get(110, "e"));
    config_.setDefault<int>("threshold", Units::get(600, "e"));
    config_.setDefault<int>("threshold_smearing", Units::get(30, "e"));

    config_.setDefault<int>("adc_resolution", 0);
    config_.setDefault<int>("adc_smearing", Units::get(300, "e"));
    config_.setDefault<int>("adc_offset", Units::get(0, "e"));
    config_.setDefault<double>("adc_slope", Units::get(10, "e"));

    config_.setDefault<bool>("output_plots", false);
}

void DefaultDigitizerModule::init() {
    if(config_.get<bool>("output_plots")) {
        LOG(TRACE) << "Creating output plots";

        // Create histograms if needed
        h_pxq = new TH1D("pixelcharge", "raw pixel charge;pixel charge [ke];pixels", 100, 0, 10);
        h_pxq_noise = new TH1D("pixelcharge_noise_", "pixel charge w/ el. noise;pixel charge [ke];pixels", 100, 0, 10);
        h_thr = new TH1D("threshold", "applied threshold; threshold [ke];events", 100, 0, 10);
        h_pxq_thr = new TH1D("pixelcharge_threshold_", "pixel charge above threshold;pixel charge [ke];pixels", 100, 0, 10);
        h_pxq_adc = new TH1D("pixelcharge_adc", "pixel charge after ADC;pixel charge [ke];pixels", 100, 0, 10);
    }

    // Conversion to ADC units requested:
    if(config_.get<int>("adc_resolution") > 0) {
        LOG(INFO) << "Converting charge to ADC units, ADC resolution: " << config_.get<int>("adc_resolution")
                  << "bit, max. value " << ((1 << config_.get<int>("adc_resolution")) - 1);
    }
}

void DefaultDigitizerModule::run(unsigned int) {
    // Loop through all pixels with charges
    std::vector<PixelHit> hits;
    for(auto& pixel_charge : pixel_message_->getData()) {
        auto pixel = pixel_charge.getPixel();
        auto pixel_index = pixel.getIndex();
        auto charge = static_cast<double>(pixel_charge.getCharge());

        LOG(DEBUG) << "Received pixel " << pixel_index << ", charge " << Units::display(charge, "e");
        if(config_.get<bool>("output_plots")) {
            h_pxq->Fill(charge / 1e3);
        }

        // Add electronics noise from Gaussian:
        std::normal_distribution<double> el_noise(0, config_.get<unsigned int>("electronics_noise"));
        charge += el_noise(random_generator_);

        LOG(DEBUG) << "Charge with noise: " << Units::display(charge, "e");
        if(config_.get<bool>("output_plots")) {
            h_pxq_noise->Fill(charge / 1e3);
        }

        // FIXME Simulate gain / gain smearing

        // Smear the threshold, Gaussian distribution around "threshold" with width "threshold_smearing"
        std::normal_distribution<double> thr_smearing(config_.get<unsigned int>("threshold"),
                                                      config_.get<unsigned int>("threshold_smearing"));
        double threshold = thr_smearing(random_generator_);
        if(config_.get<bool>("output_plots")) {
            h_thr->Fill(threshold / 1e3);
        }

        // Discard charges below threshold:
        if(charge < threshold) {
            LOG(DEBUG) << "Below smeared threshold: " << Units::display(charge, "e") << " < "
                       << Units::display(threshold, "e");
            continue;
        }

        LOG(DEBUG) << "Passed threshold: " << Units::display(charge, "e") << " > " << Units::display(threshold, "e");
        if(config_.get<bool>("output_plots")) {
            h_pxq_thr->Fill(charge / 1e3);
        }

        // Simulate ADC if resolution set to more than 0bit
        if(config_.get<int>("adc_resolution") > 0) {
            // Add ADC smearing:
            std::normal_distribution<double> adc_smearing(0, config_.get<unsigned int>("adc_smearing"));
            charge += adc_smearing(random_generator_);
            if(config_.get<bool>("output_plots")) {
                h_pxq_adc->Fill(charge / 1e3);
            }
            LOG(DEBUG) << "Smeared for simulating limited ADC sensitivity: " << Units::display(charge, "e");

            // Convert to ADC units and precision:
            charge = std::max(
                std::min(static_cast<int>(config_.get<int>("adc_offset") + charge / config_.get<double>("adc_slope")),
                         (1 << config_.get<int>("adc_resolution")) - 1),
                0);
            LOG(DEBUG) << "Charge converted to ADC units: " << charge;
        }

        // Add the hit to the hitmap
        hits.emplace_back(pixel, 0, charge, &pixel_charge);
    }

    // Output summary and update statistics
    LOG(INFO) << "Digitized " << hits.size() << " pixel hits";
    total_hits_ += hits.size();

    if(!hits.empty()) {
        // Create and dispatch hit message
        auto hits_message = std::make_shared<PixelHitMessage>(std::move(hits), getDetector());
        messenger_->dispatchMessage(this, hits_message);
    }
}

void DefaultDigitizerModule::finalize() {
    if(config_.get<bool>("output_plots")) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        h_pxq->Write();
        h_pxq_noise->Write();
        h_thr->Write();
        h_pxq_thr->Write();
        h_pxq_adc->Write();
    }

    LOG(INFO) << "Digitized " << total_hits_ << " pixel hits in total";
}
<commit_msg>Throw InvaldValueError for too high ADC precision<commit_after>/**
 * @file
 * @brief Implementation of default digitization module
 * @copyright MIT License
 */

#include "DefaultDigitizerModule.hpp"

#include "core/utils/unit.h"
#include "tools/ROOT.h"

#include <TFile.h>
#include <TH1D.h>
#include <TProfile.h>

#include "objects/PixelHit.hpp"

using namespace allpix;

DefaultDigitizerModule::DefaultDigitizerModule(Configuration config,
                                               Messenger* messenger,
                                               std::shared_ptr<Detector> detector)
    : Module(config, std::move(detector)), config_(std::move(config)), messenger_(messenger), pixel_message_(nullptr) {
    // Enable parallelization of this module if multithreading is enabled
    enable_parallelization();

    // Require PixelCharge message for single detector
    messenger_->bindSingle(this, &DefaultDigitizerModule::pixel_message_, MsgFlags::REQUIRED);

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

    // Set defaults for config variables
    config_.setDefault<int>("electronics_noise", Units::get(110, "e"));
    config_.setDefault<int>("threshold", Units::get(600, "e"));
    config_.setDefault<int>("threshold_smearing", Units::get(30, "e"));

    config_.setDefault<int>("adc_resolution", 0);
    config_.setDefault<int>("adc_smearing", Units::get(300, "e"));
    config_.setDefault<int>("adc_offset", Units::get(0, "e"));
    config_.setDefault<double>("adc_slope", Units::get(10, "e"));

    config_.setDefault<bool>("output_plots", false);
}

void DefaultDigitizerModule::init() {
    if(config_.get<bool>("output_plots")) {
        LOG(TRACE) << "Creating output plots";

        // Create histograms if needed
        h_pxq = new TH1D("pixelcharge", "raw pixel charge;pixel charge [ke];pixels", 100, 0, 10);
        h_pxq_noise = new TH1D("pixelcharge_noise_", "pixel charge w/ el. noise;pixel charge [ke];pixels", 100, 0, 10);
        h_thr = new TH1D("threshold", "applied threshold; threshold [ke];events", 100, 0, 10);
        h_pxq_thr = new TH1D("pixelcharge_threshold_", "pixel charge above threshold;pixel charge [ke];pixels", 100, 0, 10);
        h_pxq_adc = new TH1D("pixelcharge_adc", "pixel charge after ADC;pixel charge [ke];pixels", 100, 0, 10);
    }

    // Conversion to ADC units requested:
    if(config_.get<int>("adc_resolution") > 63) {
        throw InvalidValueError(config_, "adc_resolution", "precision higher than 64bit is not possible");
    }
    if(config_.get<int>("adc_resolution") > 0) {
        LOG(INFO) << "Converting charge to ADC units, ADC resolution: " << config_.get<int>("adc_resolution")
                  << "bit, max. value " << ((1 << config_.get<int>("adc_resolution")) - 1);
    }
}

void DefaultDigitizerModule::run(unsigned int) {
    // Loop through all pixels with charges
    std::vector<PixelHit> hits;
    for(auto& pixel_charge : pixel_message_->getData()) {
        auto pixel = pixel_charge.getPixel();
        auto pixel_index = pixel.getIndex();
        auto charge = static_cast<double>(pixel_charge.getCharge());

        LOG(DEBUG) << "Received pixel " << pixel_index << ", charge " << Units::display(charge, "e");
        if(config_.get<bool>("output_plots")) {
            h_pxq->Fill(charge / 1e3);
        }

        // Add electronics noise from Gaussian:
        std::normal_distribution<double> el_noise(0, config_.get<unsigned int>("electronics_noise"));
        charge += el_noise(random_generator_);

        LOG(DEBUG) << "Charge with noise: " << Units::display(charge, "e");
        if(config_.get<bool>("output_plots")) {
            h_pxq_noise->Fill(charge / 1e3);
        }

        // FIXME Simulate gain / gain smearing

        // Smear the threshold, Gaussian distribution around "threshold" with width "threshold_smearing"
        std::normal_distribution<double> thr_smearing(config_.get<unsigned int>("threshold"),
                                                      config_.get<unsigned int>("threshold_smearing"));
        double threshold = thr_smearing(random_generator_);
        if(config_.get<bool>("output_plots")) {
            h_thr->Fill(threshold / 1e3);
        }

        // Discard charges below threshold:
        if(charge < threshold) {
            LOG(DEBUG) << "Below smeared threshold: " << Units::display(charge, "e") << " < "
                       << Units::display(threshold, "e");
            continue;
        }

        LOG(DEBUG) << "Passed threshold: " << Units::display(charge, "e") << " > " << Units::display(threshold, "e");
        if(config_.get<bool>("output_plots")) {
            h_pxq_thr->Fill(charge / 1e3);
        }

        // Simulate ADC if resolution set to more than 0bit
        if(config_.get<int>("adc_resolution") > 0) {
            // Add ADC smearing:
            std::normal_distribution<double> adc_smearing(0, config_.get<unsigned int>("adc_smearing"));
            charge += adc_smearing(random_generator_);
            if(config_.get<bool>("output_plots")) {
                h_pxq_adc->Fill(charge / 1e3);
            }
            LOG(DEBUG) << "Smeared for simulating limited ADC sensitivity: " << Units::display(charge, "e");

            // Convert to ADC units and precision:
            charge = std::max(
                std::min(static_cast<int>(config_.get<int>("adc_offset") + charge / config_.get<double>("adc_slope")),
                         (1 << config_.get<int>("adc_resolution")) - 1),
                0);
            LOG(DEBUG) << "Charge converted to ADC units: " << charge;
        }

        // Add the hit to the hitmap
        hits.emplace_back(pixel, 0, charge, &pixel_charge);
    }

    // Output summary and update statistics
    LOG(INFO) << "Digitized " << hits.size() << " pixel hits";
    total_hits_ += hits.size();

    if(!hits.empty()) {
        // Create and dispatch hit message
        auto hits_message = std::make_shared<PixelHitMessage>(std::move(hits), getDetector());
        messenger_->dispatchMessage(this, hits_message);
    }
}

void DefaultDigitizerModule::finalize() {
    if(config_.get<bool>("output_plots")) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        h_pxq->Write();
        h_pxq_noise->Write();
        h_thr->Write();
        h_pxq_thr->Write();
        h_pxq_adc->Write();
    }

    LOG(INFO) << "Digitized " << total_hits_ << " pixel hits in total";
}
<|endoftext|>


<commit_before>#include "../../../SDP_Solver.hxx"

// result = \sum_p a[p] A_p,
//
// where a[p] is a vector of length primalObjective.size() and the
// constraint matrices A_p are given by
//
//   A_(j,r,s,k) = \sum_{b \in blocks[j]}
//                     Block_b(v_{b,k} v_{b,k}^T \otimes E^{rs}),
//
// where v_{b,k} is the k-th column of bilinearBases[b], as described
// in SDP.h.
//
// Inputs: sdp, a
// Output: result (overwritten)
//

void diagonal_congruence(const Real *d, const Matrix &V, const int blockRow,
                         const int blockCol, Matrix &result);

void constraint_matrix_weighted_sum(const SDP &sdp, const Vector &a,
                                    Block_Diagonal_Matrix &result)
{
  for(unsigned int j = 0; j < sdp.dimensions.size(); j++)
    {
      const int ej = sdp.degrees[j] + 1;

      // For each j, t points to the first Index_Tuple corresponding to j
      for(auto t(sdp.constraint_indices[j].begin());
          t != sdp.constraint_indices[j].end(); t += ej)
        {
          const int p = t->p;
          const int r = t->r;
          const int s = t->s;
          assert(t->k == 0);

          for(auto &b : sdp.blocks[j])
            {
              // result.blocks[b]^(r,s) = V diag(a') V^T, where
              // V=sdp.bilinearBases[b], a' denotes the subvector of a
              // corresponding to j, and M^(r,s) denotes the (r,s)-th block
              // of M.
              diagonal_congruence(&a[p], sdp.bilinear_bases[b], r, s,
                                  result.blocks[b]);

              // result should be symmetric, so if r != s, we must
              // divide the (r,s)-th block of result.blocks[b] by 2
              // and copy it to its transpose, the (s,r)-th block.
              if(r != s)
                {
                  const int u = sdp.bilinear_bases[b].rows;
                  for(int m = r * u; m < (r + 1) * u; m++)
                    {
                      for(int n = s * u; n < (s + 1) * u; n++)
                        {
                          result.blocks[b].elt(m, n) /= 2;
                          result.blocks[b].elt(n, m)
                            = result.blocks[b].elt(m, n);
                        }
                    }
                }
            }
        }
    }
}

void constraint_matrix_weighted_sum(const SDP &sdp, const Block_Matrix &a,
                                    Block_Diagonal_Matrix &result)
{
  for(size_t jj = 0; jj < sdp.dimensions.size(); ++jj)
    {
      const size_t block_size(sdp.degrees[jj] + 1);
      for(size_t block_index(2 * jj); block_index < 2 * jj + 2; ++block_index)
        {
          El::Zero(result.blocks_elemental[block_index]);
          for(size_t column_block = 0; column_block < sdp.dimensions[jj];
              ++column_block)
            for(size_t row_block = 0; row_block <= column_block; ++row_block)
              {
                size_t row_offset(
                  ((column_block * (column_block + 1)) / 2 + row_block)
                  * block_size);
                El::DistMatrix<El::BigFloat> sub_vector(
                  El::LockedView(a.blocks[jj], row_offset, 0, block_size, 1));
                El::DistMatrix<El::BigFloat> scaled_bases(
                  sdp.bilinear_bases_elemental_dist[block_index]);

                El::DiagonalScale(El::LeftOrRight::RIGHT,
                                  El::Orientation::NORMAL, sub_vector,
                                  scaled_bases);

                El::Gemm(El::Orientation::NORMAL, El::Orientation::TRANSPOSE,
                         El::BigFloat(1),
                         sdp.bilinear_bases_elemental_dist[block_index],
                         scaled_bases, El::BigFloat(0),
                         result.blocks_elemental[block_index]);
              }
        }
    }
}
<commit_msg>Use a proper result sub_block in constraint_matrix_weighted_sum<commit_after>#include "../../../SDP_Solver.hxx"

// result = \sum_p a[p] A_p,
//
// where a[p] is a vector of length primalObjective.size() and the
// constraint matrices A_p are given by
//
//   A_(j,r,s,k) = \sum_{b \in blocks[j]}
//                     Block_b(v_{b,k} v_{b,k}^T \otimes E^{rs}),
//
// where v_{b,k} is the k-th column of bilinearBases[b], as described
// in SDP.h.
//
// Inputs: sdp, a
// Output: result (overwritten)
//

void diagonal_congruence(const Real *d, const Matrix &V, const int blockRow,
                         const int blockCol, Matrix &result);

void constraint_matrix_weighted_sum(const SDP &sdp, const Vector &a,
                                    Block_Diagonal_Matrix &result)
{
  for(unsigned int j = 0; j < sdp.dimensions.size(); j++)
    {
      const int ej = sdp.degrees[j] + 1;

      // For each j, t points to the first Index_Tuple corresponding to j
      for(auto t(sdp.constraint_indices[j].begin());
          t != sdp.constraint_indices[j].end(); t += ej)
        {
          const int p = t->p;
          const int r = t->r;
          const int s = t->s;
          assert(t->k == 0);

          for(auto &b : sdp.blocks[j])
            {
              // result.blocks[b]^(r,s) = V diag(a') V^T, where
              // V=sdp.bilinearBases[b], a' denotes the subvector of a
              // corresponding to j, and M^(r,s) denotes the (r,s)-th block
              // of M.
              diagonal_congruence(&a[p], sdp.bilinear_bases[b], r, s,
                                  result.blocks[b]);

              // result should be symmetric, so if r != s, we must
              // divide the (r,s)-th block of result.blocks[b] by 2
              // and copy it to its transpose, the (s,r)-th block.
              if(r != s)
                {
                  const int u = sdp.bilinear_bases[b].rows;
                  for(int m = r * u; m < (r + 1) * u; m++)
                    {
                      for(int n = s * u; n < (s + 1) * u; n++)
                        {
                          result.blocks[b].elt(m, n) /= 2;
                          result.blocks[b].elt(n, m)
                            = result.blocks[b].elt(m, n);
                        }
                    }
                }
            }
        }
    }
}

void constraint_matrix_weighted_sum(const SDP &sdp, const Block_Matrix &a,
                                    Block_Diagonal_Matrix &result)
{
  for(size_t jj = 0; jj < sdp.dimensions.size(); ++jj)
    {
      const size_t block_size(sdp.degrees[jj] + 1);
      for(size_t block_index(2 * jj); block_index < 2 * jj + 2; ++block_index)
        {
          El::Zero(result.blocks_elemental[block_index]);
          for(size_t column_block = 0; column_block < sdp.dimensions[jj];
              ++column_block)
            for(size_t row_block = 0; row_block <= column_block; ++row_block)
              {
                const size_t result_block_size(
                  sdp.bilinear_bases_elemental_dist[block_index].Height());
                const size_t column_offset(column_block * result_block_size),
                  row_offset(row_block * result_block_size);
                size_t vector_offset(
                  ((column_block * (column_block + 1)) / 2 + row_block)
                  * block_size);
                El::DistMatrix<El::BigFloat> sub_vector(El::LockedView(
                  a.blocks[jj], vector_offset, 0, block_size, 1));
                El::DistMatrix<El::BigFloat> scaled_bases(
                  sdp.bilinear_bases_elemental_dist[block_index]);

                El::DiagonalScale(El::LeftOrRight::RIGHT,
                                  El::Orientation::NORMAL, sub_vector,
                                  scaled_bases);

                El::DistMatrix<El::BigFloat> result_sub_block(El::View(
                  result.blocks_elemental[block_index], row_offset,
                  column_offset, result_block_size, result_block_size));
                El::Gemm(El::Orientation::NORMAL, El::Orientation::TRANSPOSE,
                         El::BigFloat(1),
                         sdp.bilinear_bases_elemental_dist[block_index],
                         scaled_bases, El::BigFloat(0), result_sub_block);
              }
        }
    }
}
<|endoftext|>