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

/**
 * @file CachingFileMgrTest.cpp
 * @brief Unit tests for CachingFileMgr class.
 *
 */

#include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <fstream>
#include <iostream>

#include "DataMgr/FileMgr/CachingFileMgr.h"
#include "DataMgrTestHelpers.h"

constexpr char test_path[] = "./CacheTest";
namespace bf = boost::filesystem;
namespace fn = File_Namespace;

namespace {
void assert_dir_contains(const std::string& dir, const std::set<std::string>& files) {
  std::set<std::string> expected_files(files);
  for (const auto& file : bf::directory_iterator(dir)) {
    ASSERT_FALSE(files.find(file.path().filename().string()) == files.end())
        << "Unexpected file (" << file.path() << ") found in dir (" << dir << ")";
    expected_files.erase(file.path().filename().string());
  }
  if (!expected_files.empty()) {
    std::stringstream files_left;
    for (auto file : expected_files) {
      files_left << file << ", ";
    }
    FAIL() << "Could not find expected files: " << files_left.str();
  }
}
}  // namespace

class CachingFileMgrTest : public testing::Test {
 protected:
  // Keep page size small for these tests so we can hit limits more easily.
  static constexpr size_t page_size_ = 64;
  static constexpr size_t page_data_size_ =
      page_size_ - fn::FileBuffer::headerBufferOffset_;
  static constexpr size_t data_file_size_ =
      page_size_ * fn::CachingFileMgr::DEFAULT_NUM_PAGES_PER_DATA_FILE;
  static constexpr size_t meta_file_size_ =
      METADATA_PAGE_SIZE * fn::CachingFileMgr::DEFAULT_NUM_PAGES_PER_METADATA_FILE;
  static constexpr size_t cache_size_ = fn::DiskCacheConfig::DEFAULT_MAX_SIZE;
  static constexpr int32_t db_ = 1, tb_ = 1;
  const ChunkKey key_{db_, tb_, 1, 1};
  static constexpr size_t small_buffer_size_ = 4;
  std::vector<int8_t> small_buffer_ = std::vector<int8_t>(small_buffer_size_, -1);
  std::vector<int8_t> full_page_buffer_ = std::vector<int8_t>(page_data_size_, -1);
  fn::DiskCacheConfig disk_cache_config{test_path,
                                        fn::DiskCacheLevel::all,
                                        0,
                                        cache_size_,
                                        page_size_};
  std::string doc = std::string(1000, 'a');

  void SetUp() override {
    bf::remove_all(test_path);
    bf::create_directory(test_path);
  }
  void TearDown() override { bf::remove_all(test_path); }

  std::unique_ptr<fn::CachingFileMgr> initializeCFM(const size_t num_pages = 0) {
    auto cfm = std::make_unique<fn::CachingFileMgr>(disk_cache_config);
    // Override these defaults to hit limits more easily.
    cfm->setMaxNumDataFiles(1);
    cfm->setMaxNumMetadataFiles(1);
    cfm->setMaxWrapperSpace(1500);
    if (num_pages > 0) {
      writePages(*cfm, key_, num_pages);
    }
    return cfm;
  }

  void validatePageInfo(const fn::FileBuffer* buf,
                        const size_t num_pages,
                        const size_t num_page_versions,
                        const size_t num_meta_versions) {
    ASSERT_EQ(buf->getMultiPage().size(), num_pages);
    for (auto multi_page : buf->getMultiPage()) {
      ASSERT_EQ(multi_page.pageVersions.size(), num_page_versions);
    }
    ASSERT_EQ(buf->getMetadataPage().pageVersions.size(), num_meta_versions);
  }

  void writePages(fn::CachingFileMgr& cfm,
                  const ChunkKey& key,
                  size_t num_pages,
                  int8_t value = -1) {
    auto [db, tb] = get_table_prefix(key);
    TestHelpers::TestBuffer test_buf{
        std::vector<int8_t>(page_data_size_ * num_pages, value)};
    test_buf.clearDirtyBits();
    cfm.putBuffer(key, &test_buf);
    cfm.checkpoint(db, tb);
  }

  void writeMetaPages(fn::CachingFileMgr& cfm,
                      int32_t db,
                      int32_t tb,
                      int32_t num_pages) {
    for (int32_t i = 0; i < num_pages; ++i) {
      ChunkKey key{db, tb, 1, i};
      TestHelpers::TestBuffer test_buf{small_buffer_};
      test_buf.clearDirtyBits();
      cfm.putBuffer(key, &test_buf);
    }
    cfm.checkpoint(db, tb);
  }

  void writeWrapperFile(fn::CachingFileMgr& cfm,
                        const std::string& doc,
                        int32_t db,
                        int32_t tb) {
    cfm.writeWrapperFile(doc, db, tb);
  }

  void assertCachedMetadataEquals(
      const fn::CachingFileMgr& cfm,
      const std::vector<std::tuple<int32_t, int32_t, int32_t>>& metadata) {
    std::set<ChunkKey> expected_keys;
    for (auto [db, tb, num_keys] : metadata) {
      for (auto i = 0; i < num_keys; ++i) {
        expected_keys.emplace(ChunkKey{db, tb, 1, i});
      }
    }

    auto keys_with_metadata = cfm.getKeysWithMetadata();
    ASSERT_EQ(keys_with_metadata, expected_keys);
  }
};

TEST_F(CachingFileMgrTest, InitializeEmpty) {
  auto cfm = initializeCFM();
  assert_dir_contains(test_path, {});
}

// Epoch tests
TEST_F(CachingFileMgrTest, EpochSingleTable) {
  auto cfm = initializeCFM();
  // Create a buffer and add some values
  auto buf = cfm->createBuffer(key_);
  assert_dir_contains(std::string(test_path) + "/table_1_1", {"epoch_metadata"});
  ASSERT_EQ(cfm->epoch(1, 1), 1);
  buf->append(small_buffer_.data(), small_buffer_size_);
  cfm->checkpoint(1, 1);
  // Confirm epoch file exists
  ASSERT_EQ(cfm->epoch(1, 1), 2);
}

TEST_F(CachingFileMgrTest, EpochMultiTable) {
  auto cfm = initializeCFM();
  // Create a buffer and add some values
  auto buf1 = cfm->createBuffer(key_);
  auto buf2 = cfm->createBuffer({1, 2, 1, 1});
  buf1->append(small_buffer_.data(), small_buffer_size_);
  buf2->append(small_buffer_.data(), small_buffer_size_);
  cfm->checkpoint(1, 1);
  ASSERT_EQ(cfm->epoch(1, 1), 2);
  ASSERT_EQ(cfm->epoch(1, 2), 1);
  cfm->checkpoint(1, 2);
  ASSERT_EQ(cfm->epoch(1, 1), 2);
  ASSERT_EQ(cfm->epoch(1, 2), 2);
  cfm->checkpoint(1, 1);
  ASSERT_EQ(cfm->epoch(1, 1), 3);
  ASSERT_EQ(cfm->epoch(1, 2), 2);
}

// Initialization tests
TEST_F(CachingFileMgrTest, InitializeFromCheckpointedData) {
  std::vector<int8_t> read_buffer(4);
  {
    auto cfm = initializeCFM();
    auto buf = cfm->createBuffer(key_);
    buf->append(small_buffer_.data(), small_buffer_size_);
    cfm->checkpoint(1, 1);
  }
  auto cfm = initializeCFM();
  ASSERT_EQ(cfm->epoch(1, 1), 2);
  auto buffer = cfm->getBuffer(key_);
  ASSERT_EQ(buffer->pageCount(), 1U);
  ASSERT_EQ(buffer->numMetadataPages(), 1U);
  ASSERT_EQ(buffer->size(), 4U);
  buffer->read(read_buffer.data(), 4);
  ASSERT_EQ(read_buffer, small_buffer_);
}

TEST_F(CachingFileMgrTest, InitializeFromUncheckpointedData) {
  std::vector<int8_t> read_buffer(4);
  {
    auto cfm = initializeCFM();
    auto buf = cfm->createBuffer(key_);
    buf->append(small_buffer_.data(), small_buffer_size_);
  }
  auto cfm = initializeCFM();
  // When creating a new CFM, if we find an existing epoch for a table (even if there is
  // no table data) we will increment the epoch after reading it, so we will always be on
  // a new epoch (hence epoch = 1 despite never having checkpointed any data).
  ASSERT_EQ(cfm->epoch(1, 1), 1);
  ASSERT_FALSE(cfm->isBufferOnDevice(key_));
}

TEST_F(CachingFileMgrTest, InitializeFromPartiallyCheckpointedData) {
  std::vector<int8_t> overwrite_buffer{5, 6, 7, 8};
  std::vector<int8_t> read_buffer(4);
  {
    auto cfm = initializeCFM();
    auto buf = cfm->createBuffer(key_);
    buf->append(small_buffer_.data(), small_buffer_size_);
    cfm->checkpoint(1, 1);
    buf->append(overwrite_buffer.data(), 4);
  }
  auto cfm = initializeCFM();
  ASSERT_EQ(cfm->epoch(1, 1), 2);
  auto buffer = cfm->getBuffer(key_);
  ASSERT_EQ(buffer->pageCount(), 1U);
  ASSERT_EQ(buffer->numMetadataPages(), 1U);
  ASSERT_EQ(buffer->size(), 4U);
  buffer->read(read_buffer.data(), small_buffer_size_);
  ASSERT_EQ(read_buffer, small_buffer_);
}

TEST_F(CachingFileMgrTest, InitializeFromPartiallyFreedDataLastPage) {
  {
    auto temp_cfm = initializeCFM(2);
    auto buffer = temp_cfm->getBuffer(key_);
    buffer->freePage(buffer->getMultiPage().back().current().page);
  }
  auto cfm = initializeCFM();
  auto buffer = cfm->getBuffer(key_);
  ASSERT_EQ(buffer->size(), (page_data_size_)*2);
  ASSERT_EQ(buffer->pageCount(), 0U);
  ASSERT_EQ(buffer->numMetadataPages(), 1U);
}

TEST_F(CachingFileMgrTest, InitializeFromPartiallyFreedDataFirstPage) {
  {
    auto temp_cfm = initializeCFM(2);
    auto buffer = temp_cfm->getBuffer(key_);
    buffer->freePage(buffer->getMultiPage().front().current().page);
  }
  auto cfm = initializeCFM();
  auto buffer = cfm->getBuffer(key_);
  ASSERT_EQ(buffer->size(), (page_data_size_)*2);
  ASSERT_EQ(buffer->pageCount(), 0U);
  ASSERT_EQ(buffer->numMetadataPages(), 1U);
}

TEST_F(CachingFileMgrTest, InitializeFromFreedMetadata) {
  {
    auto temp_cfm = initializeCFM(2);
    auto buffer = temp_cfm->getBuffer(key_);
    buffer->freePage(buffer->getMetadataPage().current().page);
  }
  auto cfm = initializeCFM();
  ASSERT_FALSE(cfm->isBufferOnDevice(key_));
  ASSERT_EQ(cfm->getNumChunks(), 0U);
}

// Tests to make sure we only have one version of data in the CFM
TEST_F(CachingFileMgrTest, SingleVersion_SinglePage) {
  auto cfm = initializeCFM();
  auto buf = cfm->createBuffer(key_);
  buf->append(full_page_buffer_.data(), page_data_size_);
  cfm->checkpoint(db_, tb_);
  validatePageInfo(buf, 1, 1, 1);
}

TEST_F(CachingFileMgrTest, SingleVersion_TwoPages_SingleCheckpoint) {
  auto cfm = initializeCFM();
  auto buf = cfm->createBuffer(key_);
  buf->append(full_page_buffer_.data(), page_data_size_);
  buf->append(full_page_buffer_.data(), page_data_size_);
  cfm->checkpoint(db_, tb_);
  validatePageInfo(buf, 2, 1, 1);
}

TEST_F(CachingFileMgrTest, SingleVersion_TwoPages_TwoCheckpoints) {
  auto cfm = initializeCFM();
  auto buf = cfm->createBuffer(key_);
  buf->append(full_page_buffer_.data(), page_data_size_);
  cfm->checkpoint(db_, tb_);
  buf->append(full_page_buffer_.data(), page_data_size_);
  cfm->checkpoint(db_, tb_);
  validatePageInfo(buf, 2, 1, 1);
}

// Test how chunks are evicted - data is evicted on the chunk-level.
class ChunkEvictionTest : public CachingFileMgrTest {};

TEST_F(ChunkEvictionTest, SameTable) {
  auto cfm = initializeCFM();
  writePages(*cfm, {1, 1, 1, 1}, 128);
  writePages(*cfm, {1, 1, 1, 2}, 128);
  writePages(*cfm, {1, 1, 1, 3}, 128);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 1})->pageCount(), 0U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 2})->pageCount(), 128U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 3})->pageCount(), 128U);
}

TEST_F(ChunkEvictionTest, LargeChunk) {
  auto cfm = initializeCFM();
  writePages(*cfm, {1, 1, 1, 1}, 128);
  writePages(*cfm, {1, 1, 1, 2}, 128);
  writePages(*cfm, {1, 1, 1, 3}, 256);
  writePages(*cfm, {1, 1, 1, 1}, 64);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 1})->pageCount(), 64U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 2})->pageCount(), 0U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 3})->pageCount(), 0U);
}

TEST_F(ChunkEvictionTest, ChunkReusesPagesIfOverwritten) {
  auto cfm = initializeCFM();
  writePages(*cfm, {1, 1, 1, 1}, 256);
  writePages(*cfm, {1, 1, 1, 1}, 256, 64);
  auto buf = cfm->getBuffer({1, 1, 1, 1});
  ASSERT_EQ(buf->pageCount(), 256U);
  std::vector<int8_t> vec(4);
  buf->read(vec.data(), 4);
  ASSERT_EQ(vec, std::vector<int8_t>(4, 64));
}

TEST_F(ChunkEvictionTest, MultipleTables) {
  auto cfm = initializeCFM();
  writePages(*cfm, {1, 1, 1, 1}, 128);
  writePages(*cfm, {1, 2, 1, 1}, 128);
  writePages(*cfm, {1, 1, 1, 2}, 128);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 1})->pageCount(), 0U);
  ASSERT_EQ(cfm->getBuffer({1, 2, 1, 1})->pageCount(), 128U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 2})->pageCount(), 128U);
}

TEST_F(ChunkEvictionTest, MetadataOnlyChunkInQueue) {
  auto cfm = initializeCFM();
  cfm->createBuffer({1, 1, 1, 1});  // No chunk data
  writePages(*cfm, {1, 1, 1, 2}, 256);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 1})->pageCount(), 0U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 2})->pageCount(), 256U);
  // If we don't handle empty chunks correctly, i.e. skip them, then we will crash on this
  // line as the cache tries to evict a chunk with no data.
  writePages(*cfm, {1, 1, 1, 3}, 1);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 1})->pageCount(), 0U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 2})->pageCount(), 0U);
  ASSERT_EQ(cfm->getBuffer({1, 1, 1, 3})->pageCount(), 1U);
}

// Test how metadata is evicted - metadata is evicted on the table-level.
class MetadataEvictionTest : public CachingFileMgrTest {};

TEST_F(MetadataEvictionTest, WholeTable) {
  auto cfm = initializeCFM();
  writeMetaPages(*cfm, 1, 1, fn::CachingFileMgr::DEFAULT_NUM_PAGES_PER_METADATA_FILE);
  assertCachedMetadataEquals(
      *cfm, {{1, 1, fn::CachingFileMgr::DEFAULT_NUM_PAGES_PER_METADATA_FILE}});
  writeMetaPages(*cfm, 1, 2, 1);
  assertCachedMetadataEquals(*cfm, {{1, 2, 1}});  // Other table has been evicted
}

TEST_F(MetadataEvictionTest, MultipleTable) {
  auto cfm = initializeCFM();
  writeMetaPages(*cfm, 1, 1, 1024);  // Will get evicted
  writeMetaPages(*cfm, 1, 2, 1024);
  writeMetaPages(*cfm, 1, 3, 1024);
  writeMetaPages(*cfm, 1, 4, 1024);
  writeMetaPages(*cfm, 1, 5, 1);
  assertCachedMetadataEquals(*cfm, {{1, 2, 1024}, {1, 3, 1024}, {1, 4, 1024}, {1, 5, 1}});
}

// Verifies that deleting a buffer does not remove the table from the eviction queue if
// there are additional chunks in the table.
TEST_F(MetadataEvictionTest, ChunkDeletedFromLargeTable) {
  auto cfm = initializeCFM();
  writeMetaPages(*cfm, 1, 1, 1024);
  cfm->deleteBufferIfExists({1, 1, 1, 1023});
  writeMetaPages(*cfm, 1, 2, 512);
  writeMetaPages(*cfm, 1, 3, 512);
  writeMetaPages(*cfm, 1, 4, 1024);
  writeMetaPages(*cfm, 1, 5, 1024);
  writeMetaPages(*cfm, 1, 6, 1);
  // Deletion should have made space for an extra chunk without evicting a table
  assertCachedMetadataEquals(
      *cfm,
      {{1, 1, 1023}, {1, 2, 512}, {1, 3, 512}, {1, 4, 1024}, {1, 5, 1024}, {1, 6, 1}});
  writeMetaPages(*cfm, 1, 7, 1);  // table {1,1} should now be evicted.
  assertCachedMetadataEquals(
      *cfm, {{1, 2, 512}, {1, 3, 512}, {1, 4, 1024}, {1, 5, 1024}, {1, 6, 1}, {1, 7, 1}});
}

TEST_F(MetadataEvictionTest, ChunkDeletedFromSmallTable) {
  auto cfm = initializeCFM();
  writeMetaPages(*cfm, 1, 1, 1);
  // deleting this chunk should remove the table from the eviction queue
  cfm->deleteBufferIfExists({1, 1, 1, 0});
  writeMetaPages(*cfm, 1, 2, 1024);
  writeMetaPages(*cfm, 1, 3, 1024);
  writeMetaPages(*cfm, 1, 4, 1024);
  writeMetaPages(*cfm, 1, 5, 1024);
  assertCachedMetadataEquals(*cfm,
                             {{1, 2, 1024}, {1, 3, 1024}, {1, 4, 1024}, {1, 5, 1024}});
  // Deletion should have made space for an extra chunk without evicting a table
  writeMetaPages(*cfm, 1, 6, 1);
  assertCachedMetadataEquals(*cfm, {{1, 3, 1024}, {1, 4, 1024}, {1, 5, 1024}, {1, 6, 1}});
}

class WrapperEvictionTest : public CachingFileMgrTest {};

TEST_F(WrapperEvictionTest, WrapperWritten) {
  auto cfm = initializeCFM();
  writeWrapperFile(*cfm, doc, 1, 1);
  ASSERT_TRUE(boost::filesystem::exists(cfm->getFileMgrBasePath() +
                                        "/table_1_1/wrapper_metadata.json"));
}

TEST_F(WrapperEvictionTest, WrapperWrittenAfterEvictingAnother) {
  auto cfm = initializeCFM();
  writeMetaPages(*cfm, 1, 1, 1);  // Force allocation of a meta file and data file.
  writeMetaPages(*cfm, 1, 2, 1);
  writeWrapperFile(*cfm, doc, 1, 1);
  writeWrapperFile(*cfm, doc, 1, 2);
  ASSERT_FALSE(boost::filesystem::exists(cfm->getFileMgrBasePath() +
                                         "/table_1_1/wrapper_metadata.json"));
  ASSERT_TRUE(boost::filesystem::exists(cfm->getFileMgrBasePath() +
                                        "/table_1_2/wrapper_metadata.json"));
  assertCachedMetadataEquals(*cfm, {{1, 2, 1}});
}

TEST_F(WrapperEvictionTest, WrapperWrittenAfterEvictingMultiples) {
  auto cfm = initializeCFM();
  writeMetaPages(*cfm, 1, 1, 1);  // Force allocation of a meta file and data file.
  writeMetaPages(*cfm, 1, 2, 1);
  writeMetaPages(*cfm, 1, 3, 1);
  writeWrapperFile(*cfm, doc, 1, 1);
  writeWrapperFile(*cfm, doc, 1, 2);
  writeWrapperFile(*cfm, doc, 1, 3);
  ASSERT_FALSE(boost::filesystem::exists(cfm->getFileMgrBasePath() +
                                         "/table_1_1/wrapper_metadata.json"));
  ASSERT_FALSE(boost::filesystem::exists(cfm->getFileMgrBasePath() +
                                         "/table_1_2/wrapper_metadata.json"));
  ASSERT_TRUE(boost::filesystem::exists(cfm->getFileMgrBasePath() +
                                        "/table_1_3/wrapper_metadata.json"));
  assertCachedMetadataEquals(*cfm, {{1, 3, 1}});
}

class SizeTest : public CachingFileMgrTest {};

// Currently the minimum size is deteremined by the minimum metadata size requirements.
TEST_F(SizeTest, MinMetadataSize) {
  // The cache needs to be at least big enough to create one metadata file within the
  // assigned percentage, so this is the smallest cache we can reasonably make.  Based on
  // the current file size ratios, the smallest usable cache size is based on the metadata
  // file.
  size_t min_cache_size =
      meta_file_size_ / fn::CachingFileMgr::METADATA_FILE_SPACE_PERCENTAGE;
  fn::DiskCacheConfig config{
      test_path, fn::DiskCacheLevel::all, 0, min_cache_size, page_size_};
  auto cfm = fn::CachingFileMgr(config);

  ASSERT_EQ(cfm.getMaxWrapperSize(),
            (min_cache_size * fn::CachingFileMgr::METADATA_SPACE_PERCENTAGE) -
                (min_cache_size * fn::CachingFileMgr::METADATA_FILE_SPACE_PERCENTAGE));
  ASSERT_EQ(cfm.getMaxMetaFiles(), 1U);
}

TEST_F(SizeTest, DefaultSize) {
  fn::DiskCacheConfig config{
      test_path, fn::DiskCacheLevel::all, 0, cache_size_, DEFAULT_PAGE_SIZE};
  auto cfm = fn::CachingFileMgr(config);
  ASSERT_EQ(cfm.getMaxWrapperSize(),
            (cache_size_ * fn::CachingFileMgr::METADATA_SPACE_PERCENTAGE) -
                (cache_size_ * fn::CachingFileMgr::METADATA_FILE_SPACE_PERCENTAGE));
  auto meta_space = fn::DiskCacheConfig::DEFAULT_MAX_SIZE *
                    fn::CachingFileMgr::METADATA_SPACE_PERCENTAGE;
  auto data_file_space = fn::DiskCacheConfig::DEFAULT_MAX_SIZE - meta_space;
  auto meta_file_space = fn::DiskCacheConfig::DEFAULT_MAX_SIZE *
                         fn::CachingFileMgr::METADATA_FILE_SPACE_PERCENTAGE;
  ASSERT_EQ(cfm.getMaxDataFiles(), data_file_space / cfm.getDataFileSize());
  ASSERT_EQ(cfm.getMaxMetaFiles(), meta_file_space / cfm.getMetadataFileSize());
}

TEST_F(SizeTest, ChunkSpace) {
  auto cfm = initializeCFM();
  ASSERT_EQ(cfm->getChunkSpaceReservedByTable(1, 1), 0U);
  writePages(*cfm, {1, 1, 1, 1}, 2);
  ASSERT_EQ(cfm->getChunkSpaceReservedByTable(1, 1), page_size_ * 2);
}

TEST_F(SizeTest, MetaSpace) {
  auto cfm = initializeCFM();
  ASSERT_EQ(cfm->getMetadataSpaceReservedByTable(1, 1), 0U);
  writeMetaPages(*cfm, 1, 1, 2);
  ASSERT_EQ(cfm->getMetadataSpaceReservedByTable(1, 1), METADATA_PAGE_SIZE * 2U);
}

TEST_F(SizeTest, WrapperSpace) {
  auto cfm = initializeCFM();
  ASSERT_EQ(cfm->getTableFileMgrSpaceReserved(1, 1), 0U);
  writeWrapperFile(*cfm, doc, 1, 1);
  ASSERT_EQ(cfm->getTableFileMgrSpaceReserved(1, 1),
            boost::filesystem::file_size(cfm->getFileMgrBasePath() +
                                         "/table_1_1/wrapper_metadata.json") +
                Epoch::byte_size());
}

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  int err{0};
  try {
    err = RUN_ALL_TESTS();
  } catch (const std::exception& e) {
    LOG(ERROR) << e.what();
  }
  return err;
}

max_stars_repo_name: omnisci/mapd-core

max_issues_repo_name: omnisci/mapd-core

max_forks_repo_name: omnisci/mapd-core


text:
#define BOOST_TEST_MODULE pcraster model_engine reportvisitor
#include <boost/test/unit_test.hpp>
#include "calc_reportvisitor.h"
#include "calc_stringparser.h"
#include "calc_reporttable.h"
#include "calc_astpar.h"

BOOST_AUTO_TEST_CASE(testPos)
{
  using namespace calc;

  struct M {
   private:
     ASTNode    *d_code;
   public:
     ReportPars  d_rps;
     M(const std::string& code, bool reportLastAssOfEverySymbol):
       d_code(StringParser::createCodeAsNode(code))
     {
       ReportTable emptyRT;
       ReportVisitor rv(
         reportLastAssOfEverySymbol,
         emptyRT,Timer());
       d_code->accept(rv);
       d_rps = rv.reportPars();
     }
     ~M() {
       delete d_code;
     }
     bool posEqual(std::string const& name, std::string const& pos) const {
     if (!d_rps.count(name))
         return false;
     ReportPars::const_iterator i=d_rps.find(name);
     std::string parPos=i->second.d_par->shortPosText();
     return parPos.compare(pos)==0;
    }
  };

  { // explicit report, first reported
      M m("report p=inp1s.map+0;p=p+2;",false);
      //   1245678901234567890123456
      BOOST_CHECK(m.d_rps.count("p"));
      BOOST_CHECK(m.posEqual("p","line '1:8'"));
  }
  { // explicit report BUT last ass reported
      M m("report p=inp1s.map+0;p=p+2;",true);
      //   12345678901234567890123456
      BOOST_CHECK(m.d_rps.count("p"));
      BOOST_CHECK(m.posEqual("p","line '1:22'"));
  }
  { // no explicit set, and No  last ass reported
      M m("p=inp1s.map+0;p=p+2;",false);
      BOOST_CHECK(!m.d_rps.count("p"));
  }
  { // no explicit set, but last ass reported
      M m("p=inp1s.map+0;p=p+2;",true);
      //   1234567890123456
      BOOST_CHECK(m.d_rps.count("p"));
      BOOST_CHECK(m.posEqual("p","line '1:15'"));
  }
}

ext: cc

max_stars_repo_name: quanpands/wflow

max_issues_repo_name: quanpands/wflow

max_forks_repo_name: quanpands/wflow


text:
#ifndef SHASTA_LOCAL_ALIGNMENT_GRAPH_HPP
#define SHASTA_LOCAL_ALIGNMENT_GRAPH_HPP

/*******************************************************************************

The local alignment graph is a local subgraph of the global alignment graph,
starting at a given oriented read and going out up to a specified distance.
It is an undirected graph in which each vertex corresponds to a read.
An edge is created between two vertices if the corresponding
oriented reads have a stored alignment.

The alignment graph is being phased out in favor of the read graph
(see AssemblerReadGraph.cpp).

*******************************************************************************/

// Shasta.
#include "Alignment.hpp"
#include "computeLayout.hpp"
#include "OrientedReadPair.hpp"

// Boost libraries.
#include <boost/graph/adjacency_list.hpp>

// Standard libraries.
#include <map>

namespace shasta {

    class LocalAlignmentGraphVertex;
    class LocalAlignmentGraphEdge;
    class LocalAlignmentGraph;
    using LocalAlignmentGraphBaseClass = boost::adjacency_list<
        boost::setS,
        boost::listS,
        boost::undirectedS,
        LocalAlignmentGraphVertex,
        LocalAlignmentGraphEdge
        >;

}

class shasta::LocalAlignmentGraphVertex {
public:

    // The OrientedReadId that this vertex corresponds to.
    // We store it as OrientedRead::Int so we can also use
    // it as a vertex id for graphviz output.
    OrientedReadId::Int orientedReadId;

    // The number of bases in this read.
    uint32_t baseCount;

    // Layout position of this vertex, for display.
    array<double, 2> position;

    // The distance of this vertex from the starting vertex.
    uint32_t distance;

    LocalAlignmentGraphVertex(
        OrientedReadId orientedReadId,
        uint32_t baseCount,
        uint32_t distance) :
        orientedReadId(orientedReadId.getValue()),
        baseCount(baseCount),
        distance(distance)
        {}

};

class shasta::LocalAlignmentGraphEdge {
public:

    // Copies of the AlignmentInfo that caused this edge to be created.
    AlignmentInfo alignmentInfo;

    LocalAlignmentGraphEdge(
        const AlignmentInfo& alignmentInfo) :
        alignmentInfo(alignmentInfo)
        {}
};

class shasta::LocalAlignmentGraph :
    public LocalAlignmentGraphBaseClass {
public:

    void addVertex(
        OrientedReadId orientedReadId,
        uint32_t baseCount,
        uint32_t distance);

    void addEdge(
        OrientedReadId orientedReadId0,
        OrientedReadId orientedReadId1,
        const AlignmentInfo&);

    // Find out if a vertex with a given OrientedId exists.
    bool vertexExists(OrientedReadId) const;

    // Get the distance of an existing vertex from the start vertex.
    uint32_t getDistance(OrientedReadId) const;

    // Compute sfdp layout using graphviz and store the results
    // in the vertex positions.
    ComputeLayoutReturnCode computeLayout(
        const string& layoutMethod,
        double timeout);

    // Write directly to svg, without using Graphviz rendering.
    // This assumes that the layout was already computed
    // and stored in the vertices.
    void writeSvg(
        const string& svgId,
        uint64_t width,
        uint64_t height,
        double vertexScalingFactor,
        double edgeThicknessScalingFactor,
        uint64_t maxDistance,
        ostream& svg) const;

    // Write in Graphviz format.
    void write(ostream&, uint32_t maxDistance) const;
    void write(const string& fileName, uint32_t maxDistance) const;

private:

    // Map that gives the vertex corresponding to an OrientedReadId.
    std::map<OrientedReadId, vertex_descriptor> vertexMap;

    // Graphviz writer.
    class Writer {
    public:
        Writer(const LocalAlignmentGraph&, uint32_t maxDistance);
        void operator()(ostream&) const;
        void operator()(ostream&, vertex_descriptor) const;
        void operator()(ostream&, edge_descriptor) const;
        const LocalAlignmentGraph& graph;
        uint32_t maxDistance;
    };
};

#endif

ext: hpp

max_stars_repo_name: AustinHartman/shasta

max_issues_repo_name: AustinHartman/shasta

max_forks_repo_name: AustinHartman/shasta


text:
// File: vector.cpp

#include <iostream>
#include <boost/numeric/mtl/mtl.hpp>

template <typename Vector>
void fill_and_print(Vector& v, const char* name)
{
    // Set values in traditional way and print them
    v= 1.2, 3.4, 5.6;
    std::cout << name << " is " << v << "\n";
}

int main(int, char**)
{
#if defined(MTL_WITH_VARIADIC_TEMPLATE) && defined(MTL_WITH_TEMPLATE_ALIAS)
    using namespace mtl;

    // Regular vector
    vector<double>                                  v1(3);
    fill_and_print(v1, "v1");

    // Row vector
    vector<double, row_major>                       v2(3);
    fill_and_print(v2, "v2");

    // Fixed-size vector
    vector<double, dim<3> >                         v3;
    fill_and_print(v3, "v3");
#endif
    return 0;
}

ext: cpp


text:
//---------------------------------------------------------------------------//
//!
//! \file   Utility_LoggingHelper.hpp
//! \author Alex Robinson
//! \brief  Logging helper class declaration
//!
//---------------------------------------------------------------------------//

#ifndef UTILITY_LOGGING_HELPER_HPP
#define UTILITY_LOGGING_HELPER_HPP

// Std Lib Includes
#include <iostream>
#include <vector>
#include <string>

// Boost Includes
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/core/null_deleter.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/async_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/sources/basic_logger.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/attributes/constant.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/keyword.hpp>
#include <boost/log/expressions/formatters/named_scope.hpp>

// FRENSIE Includes
#include "Utility_LogRecordType.hpp"
#include "Utility_FancyTextOStreamBackend.hpp"
#include "Utility_LoggingStaticConstants.hpp"

// Declare public global attributes
BOOST_LOG_ATTRIBUTE_KEYWORD( record_type_log_attr,
                             FRENSIE_LOG_RECORD_TYPE_ATTR_KEYWORD,
                             Utility::LogRecordType );
BOOST_LOG_ATTRIBUTE_KEYWORD( tag_log_attr,
                             FRENSIE_LOG_TAG_ATTR_KEYWORD,
                             std::string );

/*! \defgroup frensie_logging FRENSIE Logging.
 *
 * FRENSIE Logging is done through a series of macros that are designed to
 * hide the implementation details of the logs and also allow for certain
 * log details to be ignored with no associated overhead (see the
 * Logging Macros).
 *
 * For those that are interest about the implementation of FRENSIE logging,
 * please note that we have simply wrapped much of the boost::log interface.
 * Some features that we deemed to be unnecessary for FRENSIE have been
 * hidden by our wrapper interface. We have also simplified the log setup
 * somewhat with our interface. As mentioned above, our interface also
 * allows for certain logging features to be turned off at configure time,
 * which can be important for performance since logging does incur some
 * overhead.
 */

namespace Utility{

/*! The logging helper class
 *
 * This class is primarily used as a backend for the FRENSIE logging
 * methods that cannot be inlined (e.g. log setup methods, logger attribute
 * methods, filter setting methods, etc.).
 * \ingroup frensie_logging
 */
class LoggingHelper
{

private:

  // Typedef for basic text sink backend type
  typedef boost::log::sinks::text_ostream_backend BasicTextSinkBackend;

  // Typedef for fancy text sink backend type
  typedef FancyTextOStreamBackend FancyTextSinkBackend;

  // Typedef for the basic text asynchronous sink type
  typedef boost::log::sinks::asynchronous_sink<BasicTextSinkBackend> BasicTextAsyncSink;

  // Typedef for the basic text synchronous sink type
  typedef boost::log::sinks::synchronous_sink<BasicTextSinkBackend>  BasicTextSyncSink;

  // Typedef for the fancy text asynchronous sink type
  typedef boost::log::sinks::asynchronous_sink<FancyTextSinkBackend> FancyTextAsyncSink;

  // Typedef for the fancy text synchronous sink type
  typedef boost::log::sinks::synchronous_sink<FancyTextSinkBackend> FancyTextSyncSink;

public:

  //! Typedef for the standard logger type
typedef boost::log::sources::severity_logger<Utility::LogRecordType> StandardLoggerType;

  //! Add standard global attributes
  static void addStandardGlobalAttributes();

  //! Add a global log filter
  template<typename FilterExpression>
  static void addGlobalLogFilter( FilterExpression expr );

  //! Add standard log sinks using the requested output stream
  static void addStandardLogSinks( const boost::shared_ptr<std::ostream>& os,
                                   const bool asynchronous = true );

  //! Add standard log sinks using the requested console stream
  static void addStandardLogSinks( std::ostream& console_os,
                                   const bool asynchronous = true );

  //! Add standard log sinks using the requested output streams
  template<template<typename,typename...> class STLCompliantArray>
  static void addStandardLogSinks(
         const STLCompliantArray<boost::shared_ptr<std::ostream> >& os_array,
         const bool asynchronous = true );

  //! Add a standard error log sink using the requested output stream
  static void addStandardErrorLogSink(
                                   const boost::shared_ptr<std::ostream>& os,
                                   const bool asynchronous = true );

  //! Add a standard error log sink using the console stream
  static void addStandardErrorLogSink( std::ostream& console_os,
                                       const bool asynchronous = true );

  //! Add a standard error log sink using the requested output streams
  template<template<typename,typename...> class STLCompliantArray>
  static void addStandardErrorLogSink(
         const STLCompliantArray<boost::shared_ptr<std::ostream> >& os_array,
         const bool asynchronous = true );

  //! Add a standard warning log sink using the requested output stream
  static void addStandardWarningLogSink(
                                   const boost::shared_ptr<std::ostream>& os,
                                   const bool asynchronous = true );

  //! Add a standard warning log sink using the requested console stream
  static void addStandardWarningLogSink( std::ostream& console_os,
                                         const bool asynchronous = true );

  //! Add a standard warning log sink using the requested output streams
  template<template<typename,typename...> class STLCompliantArray>
  static void addStandardWarningLogSink(
         const STLCompliantArray<boost::shared_ptr<std::ostream> >& os_array,
         const bool asynchronous = true );

  //! Add a standard notification log sink using the requested output stream
  static void addStandardNotificationLogSink(
                                   const boost::shared_ptr<std::ostream>& os,
                                   const bool asynchronous = true );

  //! Add a standard notification log sink using the requested console stream
  static void addStandardNotificationLogSink( std::ostream& console_os,
                                              const bool asynchronous = true );

  //! Add a standard notification log sink using the requested output streams
  template<template<typename,typename...> class STLCompliantArray>
  static void addStandardNotificationLogSink(
         const STLCompliantArray<boost::shared_ptr<std::ostream> >& os_array,
         const bool asynchronous = true );

  //! Remove all log sinks
  static void removeAllLogSinks();

  //! Flush all sinks
  static void flushAllLogSinks();

  //! Add a tag to the logger
  template<typename Logger>
  static void addTagToLogger( const std::string& tag, Logger& logger );

private:

  // Initialize and add error log sink
  template<typename Sink>
  static void initializeAndAddErrorLogSink(
                 const boost::shared_ptr<FancyTextSinkBackend>& sink_backend );

  // Initialize and add warning log sink
  template<typename Sink>
  static void initializeAndAddWarningLogSink(
                 const boost::shared_ptr<FancyTextSinkBackend>& sink_backend );

  // Initialize and add notification log sink
  template<typename Sink>
  static void initializeAndAddNotificationLogSink(
                 const boost::shared_ptr<FancyTextSinkBackend>& sink_backend );
};

} // end Utility namespace

//---------------------------------------------------------------------------//
// Template Includes.
//---------------------------------------------------------------------------//

#include "Utility_LoggingHelper_def.hpp"

//---------------------------------------------------------------------------//

#endif // end UTILITY_LOGGING_HELPER_HPP

//---------------------------------------------------------------------------//
// end Utility_LoggingHelper.hpp
//---------------------------------------------------------------------------//


text:
//
// null_buffers_op.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP
#define BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include <boost/asio/detail/push_options.hpp>

#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/reactor_op.hpp>

namespace boost {
namespace asio {
namespace detail {

template <typename Handler>
class null_buffers_op : public reactor_op
{
public:
  null_buffers_op(Handler handler)
    : reactor_op(&null_buffers_op::do_perform, &null_buffers_op::do_complete),
      handler_(handler)
  {
  }

  static bool do_perform(reactor_op*)
  {
    return true;
  }

  static void do_complete(io_service_impl* owner, operation* base,
      boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
  {
    // Take ownership of the handler object.
    null_buffers_op* o(static_cast<null_buffers_op*>(base));
    typedef handler_alloc_traits<Handler, null_buffers_op> alloc_traits;
    handler_ptr<alloc_traits> ptr(o->handler_, o);

    // Make the upcall if required.
    if (owner)
    {
      // Make a copy of the handler so that the memory can be deallocated
      // before the upcall is made. Even if we're not about to make an upcall,
      // a sub-object of the handler may be the true owner of the memory
      // associated with the handler. Consequently, a local copy of the handler
      // is required to ensure that any owning sub-object remains valid until
      // after we have deallocated the memory here.
      detail::binder2<Handler, boost::system::error_code, std::size_t>
        handler(o->handler_, o->ec_, o->bytes_transferred_);
      ptr.reset();
      boost::asio::detail::fenced_block b;
      boost_asio_handler_invoke_helpers::invoke(handler, handler);
    }
  }

private:
  Handler handler_;
};

} // namespace detail
} // namespace asio
} // namespace boost

#include <boost/asio/detail/pop_options.hpp>

#endif // BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP

max_stars_repo_name: jonstewart/boost-svn

max_issues_repo_name: jonstewart/boost-svn

max_forks_repo_name: jonstewart/boost-svn


text:
#include "catch.hpp"

#include <boost/units/systems/si.hpp>

#include <UnitConvert.hpp>
using namespace UnitConvert;

/**
 * This file is used for development. As new classes are created,
 * small tests are written here so that we can try to compile and use
 * them.
 */

TEST_CASE("Dimension Devel", "[devel]")
{
  BaseDimension<Dimension::Name::Length>            L;
  BaseDimension<Dimension::Name::Mass>              M;
  BaseDimension<Dimension::Name::Time>              T;
  BaseDimension<Dimension::Name::ElectricalCurrent> I;
  BaseDimension<Dimension::Name::Temperature>       THETA;
  BaseDimension<Dimension::Name::Amount>            N;
  BaseDimension<Dimension::Name::LuminousIntensity> J;

  Dimension V = L / T;
  Dimension E = M * V * V;
  Dimension P = E / T;

  BaseDimension<Dimension::Name::Length> Length;

  CHECK(P[Dimension::Name::Length] == 2);
  CHECK(P[Dimension::Name::Mass] == 1);
  CHECK(P[Dimension::Name::Time] == -3);
  CHECK(P[Dimension::Name::ElectricalCurrent] == 0);
  CHECK(P[Dimension::Name::Temperature] == 0);
  CHECK(P[Dimension::Name::Amount] == 0);
  CHECK(P[Dimension::Name::LuminousIntensity] == 0);

  CHECK(L == Length);
  CHECK(M != Length);
  CHECK(M != L);
  CHECK(E != P);
  CHECK(E == P * T);
}

TEST_CASE("Unit Devel", "[devel]")
{
  BaseUnit<Dimension::Name::Length>      meter;
  BaseUnit<Dimension::Name::Mass>        kilogram;
  BaseUnit<Dimension::Name::Time>        second;
  BaseUnit<Dimension::Name::Temperature> kelvin;

  Unit gram = kilogram / 1000;

  Unit centimeter = meter / 100;
  Unit inch       = 2.54 * centimeter;
  Unit foot       = 12 * inch;

  Unit joule = kilogram * meter * meter / second / second;

  Unit celsius    = kelvin - 273.15;
  Unit fahrenheit = (5. / 9) * celsius + 32;

  Unit unit = celsius;

  CHECK(meter.scale() == 1);
  CHECK(meter.offset() == 0);
  CHECK(kilogram.scale() == 1);
  CHECK(kilogram.offset() == 0);
  CHECK(second.scale() == 1);
  CHECK(second.offset() == 0);
  CHECK(kelvin.scale() == 1);
  CHECK(kelvin.offset() == 0);

  CHECK(gram.scale() == Approx(0.001));
  CHECK(gram.offset() == 0);

  CHECK(centimeter.scale() == Approx(0.01));
  CHECK(centimeter.offset() == 0);
  CHECK(inch.scale() == Approx(0.0254));
  CHECK(inch.offset() == 0);
  CHECK(foot.scale() == Approx(12 * 0.0254));
  CHECK(foot.offset() == 0);

  CHECK(joule.scale() == Approx(1));
  CHECK(joule.offset() == Approx(0));

  CHECK(celsius.scale() == Approx(1));
  CHECK(celsius.offset() == Approx(-273.15));

  CHECK(fahrenheit.scale() == Approx(5. / 9));
  CHECK(fahrenheit.offset() == Approx(32 - (9. / 5) * 273.15));

  CHECK(unit.offset() == Approx(-273.15));
  unit += 100;
  CHECK(unit.offset() == Approx(-173.15));
  unit += 100;
  CHECK(unit.offset() == Approx(-73.15));
  unit -= 50;
  CHECK(unit.offset() == Approx(-123.15));

  SECTION("Quantity Devel", "[devel]")
  {
    Quantity<double> distance(100, foot);

    CHECK(distance.to(meter).value() == Approx(30.48));
    CHECK_THROWS(distance.to(second));

    Quantity<double> temperature(37, celsius);

    CHECK(temperature.to(kelvin).value() == Approx(273.15 + 37));
    CHECK(temperature.to(fahrenheit).value() == Approx(98.6));
  }
}

TEST_CASE("UnitRegistry Devel", "[devel]")
{
  UnitRegistry ureg;

  ureg.addBaseUnit<Dimension::Name::Length>("m");
  ureg.addBaseUnit<Dimension::Name::Mass>("kg");
  ureg.addBaseUnit<Dimension::Name::Time>("s");
  ureg.addBaseUnit<Dimension::Name::Temperature>("K");
  ureg.addBaseUnit<Dimension::Name::Amount>("mol");

  ureg.addUnit("100 cm = 1 m");
  ureg.addUnit("1 in = 2.54 cm");
  ureg.addUnit("1 ft = 12 in");
  ureg.addUnit("1 J = 1 kg*m^2*s^-2");
  ureg.addUnit("1 W = 1 J/s");
  ureg.addUnit("1 cal = 4.184 J");

  Unit u = BaseUnit<Dimension::Name::Dimensionless>();
  Quantity<double> q = ureg.makeQuantity<double>(200, "cm");

  u = ureg.getUnit("m");
  CHECK(u.scale() == Approx(1));
  u = ureg.getUnit("cm");
  CHECK(u.scale() == Approx(0.01));
  CHECK_THROWS(ureg.getUnit("mm"));
  u = ureg.getUnit("mm",true);
  CHECK(u.scale() == Approx(0.001));
  u = ureg.getUnit("millim",true);
  CHECK(u.scale() == Approx(0.001));

  CHECK(q.value() == Approx(200));
  // getUnit returns a unit that is in the registry
  CHECK(q.to(ureg.getUnit("m")).value() == Approx(2));
  CHECK_THROWS(q.to(ureg.getUnit("s")));

  q = ureg.makeQuantity<double>(0.25, "s");
  CHECK(q.value() == Approx(0.25));
  // makeUnit can create a unit from the registry,
  // including SI prefixed versions of the units in the registry
  CHECK(q.to(ureg.makeUnit("ms")).value() == Approx(250));
  CHECK_THROWS(q.to(ureg.getUnit("m")));

  q = ureg.makeQuantity<double>(100, "cal");
  CHECK(q.value() == Approx(100));
  // the Quantity class can convert to a unit string
  // if it was created by a UnitRegistry
  CHECK(q.to("J").value() == Approx(100 * 4.184));

  // string based conversion can convert to SI prefixed version of any unit
  // in the registry, even if they are not explicitly put in the registry,
  CHECK(q.to("mJ").value() == Approx(100 * 4.184 * 1000));

  // string based conversion can also convert to derived unit representations
  // that contain SI prefixed versions of units in the registry
  CHECK(q.to("kg*km^2/ms^2").value() == Approx(100 * 4.184 / 1e12));
  CHECK(q.to("kg*m*km/ms/s").value() == Approx(100 * 4.184 / 1e6));
  CHECK(q.to("mW*s").value() == Approx(100 * 4.184 * 1000));
  CHECK(q.to("mW*cs").value() == Approx(100 * 4.184 * 1000 * 100));

  CHECK_THROWS(q.to("m"));

  SECTION("Converting to Boost.Units quantity")
  {
    Quantity<double> distance = ureg.makeQuantity<double>(100, "ft");
    boost::units::quantity<boost::units::si::length> L =
        distance.to<boost::units::si::length>();
    CHECK(boost::units::quantity_cast<double>(L) == Approx(30.48));
  }

}

TEST_CASE("BoostUnitRegistry Devel", "[devel]")
{
  BoostUnitRegistry<boost::units::si::system> ureg;

  // base units are automatically loaded into the
  // registry.

  ureg.addUnit("100 cm = 1 m");
  ureg.addUnit("1 in = 2.54 cm");
  ureg.addUnit("1 ft = 12 in");
  ureg.addUnit("1 J = 1 kg*m^2*s^-2");
  ureg.addUnit("1 W = 1 J/s");
  ureg.addUnit("1 cal = 4.184 J");

  Quantity<double> q = ureg.makeQuantity<double>(200, "cm");

  CHECK(q.value() == Approx(200));
  // getUnit returns a unit that is in the registry
  CHECK(q.to(ureg.getUnit("m")).value() == Approx(2));
  CHECK_THROWS(q.to(ureg.getUnit("s")));

  q = ureg.makeQuantity<double>(0.25, "s");
  CHECK(q.value() == Approx(0.25));
  // makeUnit can create a unit from the registry,
  // including SI prefixed versions of the units in the registry
  CHECK(q.to(ureg.makeUnit("ms")).value() == Approx(250));
  CHECK_THROWS(q.to(ureg.getUnit("m")));

  q = ureg.makeQuantity<double>(100, "cal");
  CHECK(q.value() == Approx(100));
  // the Quantity class can convert to a unit string
  // if it was created by a UnitRegistry
  CHECK(q.to("J").value() == Approx(100 * 4.184));

  // string based conversion can convert to SI prefixed version of any unit
  // in the registry, even if they are not explicitly put in the registry,
  CHECK(q.to("mJ").value() == Approx(100 * 4.184 * 1000));

  // string based conversion can also convert to derived unit representations
  // that contain SI prefixed versions of units in the registry
  CHECK(q.to("kg*km^2/ms^2").value() == Approx(100 * 4.184 / 1e12));
  CHECK(q.to("kg*m*km/ms/s").value() == Approx(100 * 4.184 / 1e6));
  CHECK(q.to("mW*s").value() == Approx(100 * 4.184 * 1000));
  CHECK(q.to("mW*cs").value() == Approx(100 * 4.184 * 1000 * 100));

  CHECK_THROWS(q.to("m"));

  SECTION("Converting to Boost.Units quantity")
  {
    Quantity<double> distance = ureg.makeQuantity<double>(100, "ft");
    boost::units::quantity<boost::units::si::length> L =
        distance.to<boost::units::si::length>();
    CHECK(boost::units::quantity_cast<double>(L) == Approx(30.48));
  }
}


text:
/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2014- University of Edinburgh

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/

#include <algorithm>
#include <cmath>
#include <iterator>

#define BOOST_FILESYSTEM_VERSION 3
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>

#include "util/exception.hh"
#include "util/file_piece.hh"

#include "Scorer.h"
#include "HopeFearDecoder.h"

using namespace std;
namespace fs = boost::filesystem;

namespace MosesTuning
{

static const ValType BLEU_RATIO = 5;

std::pair<MiraWeightVector*,size_t>
InitialiseWeights(const string& denseInitFile, const string& sparseInitFile,
                  const string& type, bool verbose)
{
  // Dense
  vector<parameter_t> initParams;
  if(!denseInitFile.empty()) {
    ifstream opt(denseInitFile.c_str());
    string buffer;
    if (opt.fail()) {
      cerr << "could not open dense initfile: " << denseInitFile << endl;
      exit(3);
    }
    if (verbose) cerr << "Reading dense features:" << endl;
    parameter_t val;
    getline(opt,buffer);
    if (buffer.find_first_of("=") == buffer.npos) {
      UTIL_THROW_IF(type == "hypergraph", util::Exception, "For hypergraph version, require dense features in 'name= value' format");
      cerr << "WARN: dense features in deprecated Moses mert format. Prefer 'name= value' format." << endl;
      istringstream strstrm(buffer);
      while(strstrm >> val) {
        initParams.push_back(val);
        if(verbose) cerr << val << endl;
      }
    } else {
      vector<string> names;
      string last_name = "";
      size_t feature_ctr = 1;
      do {
        size_t equals = buffer.find_last_of("=");
        UTIL_THROW_IF(equals == buffer.npos, util::Exception, "Incorrect format in dense feature file: '"
                      << buffer << "'");
        string name = buffer.substr(0,equals);
        names.push_back(name);
        initParams.push_back(boost::lexical_cast<ValType>(buffer.substr(equals+2)));

        //Names for features with several values need to have their id added
        if (name != last_name) feature_ctr = 1;
        last_name = name;
        if (feature_ctr>1) {
          stringstream namestr;
          namestr << names.back() << "_" << feature_ctr;
          names[names.size()-1] = namestr.str();
          if (feature_ctr == 2) {
            stringstream namestr;
            namestr << names[names.size()-2] << "_" << (feature_ctr-1);
            names[names.size()-2] = namestr.str();
          }
        }
        ++feature_ctr;

      } while(getline(opt,buffer));

      //Make sure that SparseVector encodes dense feature names as 0..n-1.
      for (size_t i = 0; i < names.size(); ++i) {
        size_t id = SparseVector::encode(names[i]);
        assert(id == i);
        if (verbose) cerr << names[i] << " " << initParams[i] << endl;
      }

    }

    opt.close();
  }
  size_t initDenseSize = initParams.size();
  // Sparse
  if(!sparseInitFile.empty()) {
    if(initDenseSize==0) {
      cerr << "sparse initialization requires dense initialization" << endl;
      exit(3);
    }
    ifstream opt(sparseInitFile.c_str());
    if(opt.fail()) {
      cerr << "could not open sparse initfile: " << sparseInitFile << endl;
      exit(3);
    }
    int sparseCount=0;
    parameter_t val;
    std::string name;
    while(opt >> name >> val) {
      size_t id = SparseVector::encode(name) + initDenseSize;
      while(initParams.size()<=id) initParams.push_back(0.0);
      initParams[id] = val;
      sparseCount++;
    }
    cerr << "Found " << sparseCount << " initial sparse features" << endl;
    opt.close();
  }

  return pair<MiraWeightVector*,size_t>(new MiraWeightVector(initParams), initDenseSize);
}

ValType HopeFearDecoder::Evaluate(const AvgWeightVector& wv)
{
  vector<ValType> stats(scorer_->NumberOfScores(),0);
  for(reset(); !finished(); next()) {
    vector<ValType> sent;
    MaxModel(wv,&sent);
    for(size_t i=0; i<sent.size(); i++) {
      stats[i]+=sent[i];
    }
  }
  return scorer_->calculateScore(stats);
}

NbestHopeFearDecoder::NbestHopeFearDecoder(
  const vector<string>& featureFiles,
  const vector<string>&  scoreFiles,
  bool streaming,
  bool  no_shuffle,
  bool safe_hope,
  Scorer* scorer
) : safe_hope_(safe_hope)
{
  scorer_ = scorer;
  if (streaming) {
    train_.reset(new StreamingHypPackEnumerator(featureFiles, scoreFiles));
  } else {
    train_.reset(new RandomAccessHypPackEnumerator(featureFiles, scoreFiles, no_shuffle));
  }
}

void NbestHopeFearDecoder::next()
{
  train_->next();
}

bool NbestHopeFearDecoder::finished()
{
  return train_->finished();
}

void NbestHopeFearDecoder::reset()
{
  train_->reset();
}

void NbestHopeFearDecoder::HopeFear(
  const std::vector<ValType>& backgroundBleu,
  const MiraWeightVector& wv,
  HopeFearData* hopeFear
)
{

  // Hope / fear decode
  ValType hope_scale = 1.0;
  size_t hope_index=0, fear_index=0, model_index=0;
  ValType hope_score=0, fear_score=0, model_score=0;
  for(size_t safe_loop=0; safe_loop<2; safe_loop++) {
    ValType hope_bleu=0, hope_model=0;
    for(size_t i=0; i< train_->cur_size(); i++) {
      const MiraFeatureVector& vec=train_->featuresAt(i);
      ValType score = wv.score(vec);
      ValType bleu = scorer_->calculateSentenceLevelBackgroundScore(train_->scoresAt(i),backgroundBleu);
      // Hope
      if(i==0 || (hope_scale*score + bleu) > hope_score) {
        hope_score = hope_scale*score + bleu;
        hope_index = i;
        hope_bleu = bleu;
        hope_model = score;
      }
      // Fear
      if(i==0 || (score - bleu) > fear_score) {
        fear_score = score - bleu;
        fear_index = i;
      }
      // Model
      if(i==0 || score > model_score) {
        model_score = score;
        model_index = i;
      }
    }
    // Outer loop rescales the contribution of model score to 'hope' in antagonistic cases
    // where model score is having far more influence than BLEU
    hope_bleu *= BLEU_RATIO; // We only care about cases where model has MUCH more influence than BLEU
    if(safe_hope_ && safe_loop==0 && abs(hope_model)>1e-8 && abs(hope_bleu)/abs(hope_model)<hope_scale)
      hope_scale = abs(hope_bleu) / abs(hope_model);
    else break;
  }
  hopeFear->modelFeatures = train_->featuresAt(model_index);
  hopeFear->hopeFeatures = train_->featuresAt(hope_index);
  hopeFear->fearFeatures = train_->featuresAt(fear_index);

  hopeFear->hopeStats = train_->scoresAt(hope_index);
  hopeFear->hopeBleu = scorer_->calculateSentenceLevelBackgroundScore(hopeFear->hopeStats, backgroundBleu);
  const vector<float>& fear_stats = train_->scoresAt(fear_index);
  hopeFear->fearBleu = scorer_->calculateSentenceLevelBackgroundScore(fear_stats, backgroundBleu);

  hopeFear->modelStats = train_->scoresAt(model_index);
  hopeFear->hopeFearEqual = (hope_index == fear_index);
}

void NbestHopeFearDecoder::MaxModel(const AvgWeightVector& wv, std::vector<ValType>* stats)
{
  // Find max model
  size_t max_index=0;
  ValType max_score=0;
  for(size_t i=0; i<train_->cur_size(); i++) {
    MiraFeatureVector vec(train_->featuresAt(i));
    ValType score = wv.score(vec);
    if(i==0 || score > max_score) {
      max_index = i;
      max_score = score;
    }
  }
  *stats = train_->scoresAt(max_index);
}

HypergraphHopeFearDecoder::HypergraphHopeFearDecoder
(
  const string& hypergraphDir,
  const vector<string>& referenceFiles,
  size_t num_dense,
  bool streaming,
  bool no_shuffle,
  bool safe_hope,
  size_t hg_pruning,
  const MiraWeightVector& wv,
  Scorer* scorer
) :
  num_dense_(num_dense)
{

  UTIL_THROW_IF(streaming, util::Exception, "Streaming not currently supported for hypergraphs");
  UTIL_THROW_IF(!fs::exists(hypergraphDir), HypergraphException, "Directory '" << hypergraphDir << "' does not exist");
  UTIL_THROW_IF(!referenceFiles.size(), util::Exception, "No reference files supplied");
  references_.Load(referenceFiles, vocab_);

  SparseVector weights;
  wv.ToSparse(&weights,num_dense_);
  scorer_ = scorer;

  static const string kWeights = "weights";
  fs::directory_iterator dend;
  size_t fileCount = 0;

  cerr << "Reading  hypergraphs" << endl;
  for (fs::directory_iterator di(hypergraphDir); di != dend; ++di) {
    const fs::path& hgpath = di->path();
    if (hgpath.filename() == kWeights) continue;
    //  cerr << "Reading " << hgpath.filename() << endl;
    Graph graph(vocab_);
    size_t id = boost::lexical_cast<size_t>(hgpath.stem().string());
    util::scoped_fd fd(util::OpenReadOrThrow(hgpath.string().c_str()));
    //util::FilePiece file(di->path().string().c_str());
    util::FilePiece file(fd.release());
    ReadGraph(file,graph);

    //cerr << "ref length " << references_.Length(id) << endl;
    size_t edgeCount = hg_pruning * references_.Length(id);
    boost::shared_ptr<Graph> prunedGraph;
    prunedGraph.reset(new Graph(vocab_));
    graph.Prune(prunedGraph.get(), weights, edgeCount);
    graphs_[id] = prunedGraph;
    // cerr << "Pruning to v=" << graphs_[id]->VertexSize() << " e=" << graphs_[id]->EdgeSize()  << endl;
    ++fileCount;
    if (fileCount % 10 == 0) cerr << ".";
    if (fileCount % 400 ==  0) cerr << " [count=" << fileCount << "]\n";
  }
  cerr << endl << "Done" << endl;

  sentenceIds_.resize(graphs_.size());
  for (size_t i = 0; i < graphs_.size(); ++i) sentenceIds_[i] = i;
  if (!no_shuffle) {
    random_shuffle(sentenceIds_.begin(), sentenceIds_.end());
  }

}

void HypergraphHopeFearDecoder::reset()
{
  sentenceIdIter_ = sentenceIds_.begin();
}

void HypergraphHopeFearDecoder::next()
{
  sentenceIdIter_++;
}

bool HypergraphHopeFearDecoder::finished()
{
  return sentenceIdIter_ == sentenceIds_.end();
}

void HypergraphHopeFearDecoder::HopeFear(
  const vector<ValType>& backgroundBleu,
  const MiraWeightVector& wv,
  HopeFearData* hopeFear
)
{
  size_t sentenceId = *sentenceIdIter_;
  SparseVector weights;
  wv.ToSparse(&weights, num_dense_);
  const Graph& graph = *(graphs_[sentenceId]);

  // ValType hope_scale = 1.0;
  HgHypothesis hopeHypo, fearHypo, modelHypo;
  for(size_t safe_loop=0; safe_loop<2; safe_loop++) {

    //hope decode
    Viterbi(graph, weights, 1, references_, sentenceId, backgroundBleu, &hopeHypo);

    //fear decode
    Viterbi(graph, weights, -1, references_, sentenceId, backgroundBleu, &fearHypo);

    //Model decode
    Viterbi(graph, weights, 0, references_, sentenceId, backgroundBleu, &modelHypo);

    // Outer loop rescales the contribution of model score to 'hope' in antagonistic cases
    // where model score is having far more influence than BLEU
    //  hope_bleu *= BLEU_RATIO; // We only care about cases where model has MUCH more influence than BLEU
    //  if(safe_hope_ && safe_loop==0 && abs(hope_model)>1e-8 && abs(hope_bleu)/abs(hope_model)<hope_scale)
    //    hope_scale = abs(hope_bleu) / abs(hope_model);
    //  else break;
    //TODO: Don't currently get model and bleu so commented this out for now.
    break;
  }
  //modelFeatures, hopeFeatures and fearFeatures
  hopeFear->modelFeatures = MiraFeatureVector(modelHypo.featureVector, num_dense_);
  hopeFear->hopeFeatures = MiraFeatureVector(hopeHypo.featureVector, num_dense_);
  hopeFear->fearFeatures = MiraFeatureVector(fearHypo.featureVector, num_dense_);

  //Need to know which are to be mapped to dense features!

  //Only C++11
  //hopeFear->modelStats.assign(std::begin(modelHypo.bleuStats), std::end(modelHypo.bleuStats));
  vector<ValType> fearStats(scorer_->NumberOfScores());
  hopeFear->hopeStats.reserve(scorer_->NumberOfScores());
  hopeFear->modelStats.reserve(scorer_->NumberOfScores());
  for (size_t i = 0; i < fearStats.size(); ++i) {
    hopeFear->modelStats.push_back(modelHypo.bleuStats[i]);
    hopeFear->hopeStats.push_back(hopeHypo.bleuStats[i]);

    fearStats[i] = fearHypo.bleuStats[i];
  }
  /*
  cerr << "hope" << endl;;
  for (size_t i = 0; i < hopeHypo.text.size(); ++i) {
    cerr << hopeHypo.text[i]->first << " ";
  }
  cerr << endl;
  for (size_t i = 0; i < fearStats.size(); ++i) {
    cerr << hopeHypo.bleuStats[i] << " ";
  }
  cerr << endl;
  cerr << "fear";
  for (size_t i = 0; i < fearHypo.text.size(); ++i) {
    cerr << fearHypo.text[i]->first << " ";
  }
  cerr << endl;
  for (size_t i = 0; i < fearStats.size(); ++i) {
    cerr  << fearHypo.bleuStats[i] << " ";
  }
  cerr << endl;
  cerr << "model";
  for (size_t i = 0; i < modelHypo.text.size(); ++i) {
    cerr << modelHypo.text[i]->first << " ";
  }
  cerr << endl;
  for (size_t i = 0; i < fearStats.size(); ++i) {
    cerr << modelHypo.bleuStats[i] << " ";
  }
  cerr << endl;
  */
  hopeFear->hopeBleu = sentenceLevelBackgroundBleu(hopeFear->hopeStats, backgroundBleu);
  hopeFear->fearBleu = sentenceLevelBackgroundBleu(fearStats, backgroundBleu);

  //If fv and bleu stats are equal, then assume equal
  hopeFear->hopeFearEqual = true; //(hopeFear->hopeBleu - hopeFear->fearBleu) >= 1e-8;
  if (hopeFear->hopeFearEqual) {
    for (size_t i = 0; i < fearStats.size(); ++i) {
      if (fearStats[i] != hopeFear->hopeStats[i]) {
        hopeFear->hopeFearEqual = false;
        break;
      }
    }
  }
  hopeFear->hopeFearEqual = hopeFear->hopeFearEqual && (hopeFear->fearFeatures == hopeFear->hopeFeatures);
}

void HypergraphHopeFearDecoder::MaxModel(const AvgWeightVector& wv, vector<ValType>* stats)
{
  assert(!finished());
  HgHypothesis bestHypo;
  size_t sentenceId = *sentenceIdIter_;
  SparseVector weights;
  wv.ToSparse(&weights, num_dense_);
  vector<ValType> bg(scorer_->NumberOfScores());
  //cerr << "Calculating bleu on " << sentenceId << endl;
  Viterbi(*(graphs_[sentenceId]), weights, 0, references_, sentenceId, bg, &bestHypo);
  stats->resize(bestHypo.bleuStats.size());
  /*
  for (size_t i = 0; i < bestHypo.text.size(); ++i) {
    cerr << bestHypo.text[i]->first << " ";
  }
  cerr << endl;
  */
  for (size_t i = 0; i < bestHypo.bleuStats.size(); ++i) {
    (*stats)[i] = bestHypo.bleuStats[i];
  }
}

};

max_stars_repo_name: ugermann/MMT

max_issues_repo_name: Pangeamt/nectm

max_forks_repo_name: Pangeamt/nectm


text:
//
// $Id$
//
// Robert Burke <robert.burke@cshs.org>
//
// Copyright 2009 Spielberg Family Center for Applied Proteomics
//   Cedars Sinai Medical Center, Los Angeles, California  90048
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>

#include "msrun/MSRun.hpp"
#include "msrun/MSRunWriter.hpp"
#include "msmucker/MuckedMSRun.hpp"

using namespace std;
using namespace pwiz::msrun;
using namespace pwiz::msmucker;

namespace po = boost::program_options;

class MySieve : public MSRunWriter::Sieve
{
public:
    virtual bool allow(const Scan& scan) const
    {
        return true;
    }
};

struct Config
{
    string in_filename;
    string out_filename;
    long scanNumber;
    double muckAmount;

    Config()
        : scanNumber(1), muckAmount(0.)
    {}

    Config(const string& in_filename, const string& out_filename,
           long scanNumber, double muckAmount)
        : in_filename(in_filename), out_filename(out_filename),
          scanNumber(scanNumber), muckAmount(muckAmount)
    {}
};

Config processCommandLine(int argc, char** argv)
{

    Config config;

    ostringstream usage;
    usage << "Usage: msmucker [options] in_filename out_filename\n";

    // Construct the commandline parse options
    po::options_description od_config("Options");
    od_config.add_options()
        ("amount,a",
         po::value<double>(&config.muckAmount)->default_value(
             config.muckAmount),
         ": Set the amount to muck up the scan by")
        ("scan,s",
         po::value<long>(&config.scanNumber)->default_value(
             config.scanNumber),
         ": Set the scan to muck up")
         ;

    usage << od_config;

    const char* label_in_filename = "in_filename";
    const char* label_out_filename = "out_filename";

    po::options_description od_args;
    od_args.add_options()
        (label_in_filename, po::value<string>(&config.in_filename), "")
        (label_out_filename, po::value<string>(&config.out_filename), "");

    po::positional_options_description pod_args;
    pod_args.add(label_in_filename, 1);
    pod_args.add(label_out_filename, 1);

    po::options_description op_parse;
    op_parse.add(od_config).add(od_args);

    // Parse the command line

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).
              options(op_parse).positional(pod_args).run(), vm);
    po::notify(vm);

    if (config.in_filename.size() == 0 || config.out_filename.size() == 0)
        throw runtime_error(usage.str());

    return config;
}

int main(int argc, char** argv)
{
    Config config = processCommandLine(argc, argv);

    auto_ptr<MSRun> msrun = MSRun::create(config.in_filename);

    MuckedMSRun muckedmsrun(msrun, config.scanNumber, config.muckAmount);

    MySieve ms;
    auto_ptr<MSRunWriter> writer = MSRunWriter::create((MSRun*)&muckedmsrun,
                                                       config.out_filename,
                                                       &ms);

    writer->write();
}

max_stars_repo_name: austinkeller/pwiz

max_issues_repo_name: austinkeller/pwiz

max_forks_repo_name: austinkeller/pwiz


text:
/*
 * LYPineappleAction.cpp
 *
 *  Created on: 2014-9-24
 *      Author: caiqingfeng
 */

#include "LYPineappleAction.h"
#include <sstream>
#include "poker/src/LYCardHelpers.h"
#include <boost/algorithm/string.hpp>
#include <iostream>

LYPineappleAction::LYPineappleAction() {
	// TODO Auto-generated constructor stub
	applicant = LYEMPTYSEAT;
	verb = LYCMD_RESET;
	bricks.clear();
}
//bricks:"0:8,0:22,0:40,0:34,0:45"
LYPineappleAction::LYPineappleAction(const std::string& table_id,
		unsigned int applicant, const std::string& bricks, unsigned int verb, const std::string& uid) {
	// TODO Auto-generated constructor stub
	this->applicant = applicant;
	this->verb = verb;
	this->table_id = table_id;
	this->bricks.clear();
	this->player = uid;
	const char *d = ",";
	const char *d1 = ":";
	char *p;
	std::vector <char*> splited_bricks;
	p = strtok(const_cast<char*>(bricks.c_str()), d);
	while (p) {
		splited_bricks.push_back(p);
		p = strtok(NULL, d);
	}
	for (int j = 0; j < splited_bricks.size(); ++j) {
		char *p1;
		p1 = strtok(splited_bricks[j], d1);
		std::vector <std::string> brick;
		int i = 0;
		while (p1) {
			std::string s(p1);
			brick.push_back(s);
			i += 1;
			p1 = strtok(NULL, d1);
		}
		int brick_place = atoi(brick[0].c_str());
		int brick_value = atoi(brick[1].c_str());
		LYPineappleBrick temp((unsigned int) brick_place,
				(unsigned int) brick_value);
		this->bricks.push_back(temp);
	}
}

LYPineappleAction::~LYPineappleAction() {
	// TODO Auto-generated destructor stub
}

std::string LYPineappleAction::toString() {
	std::string str;
	std::ostringstream ios;
	ios << "table:" << table_id << std::endl;
	ios << "applicant:" << applicant << std::endl;
	ios << "player:" << player << std::endl;
	ios << "verb:" << verb << std::endl;
	std::vector<LYPineappleBrick>::iterator it = bricks.begin();
	for (; it != bricks.end(); it++) {
		LYPineappleBrick bk = *it;
		ios << "briks:" << bk.toString() << std::endl;
	}
	str = ios.str();
	return str;
}

void LYPineappleAction::setBricksByCards(std::vector<LYCard> &cds) {
	std::vector<LYCard>::iterator it = cds.begin();
	for (; it != cds.end(); it++) {
		LYPineappleBrick bk(LY_UNDEFINED_POSITION, *it);
		bricks.push_back(bk);
	}
}

void LYPineappleAction::issueFirstHand(std::vector<LYCard> &cds,
		const std::string& table, const std::string& uid, unsigned int seat) {
	table_id = table;
	applicant = seat;
	verb = LYCMD_ISSUE_FIRST_HAND;
	player = uid;
	setBricksByCards(cds);
}

void LYPineappleAction::issueSecondHand(std::vector<LYCard> &cds,
		const std::string& table, const std::string& uid, unsigned int seat) {
	table_id = table;
	applicant = seat;
	verb = LYCMD_ISSUE_SECOND_HAND;
	player = uid;
	setBricksByCards(cds);
}

void LYPineappleAction::issueThirdHand(std::vector<LYCard> &cds,
		const std::string& table, const std::string& uid, unsigned int seat) {
	table_id = table;
	applicant = seat;
	verb = LYCMD_ISSUE_THIRD_HAND;
	player = uid;
	setBricksByCards(cds);
}

void LYPineappleAction::issueFouthHand(std::vector<LYCard> &cds,
		const std::string& table, const std::string& uid, unsigned int seat) {
	table_id = table;
	player = uid;
	applicant = seat;
	verb = LYCMD_ISSUE_FOUTH_HAND;
	setBricksByCards(cds);
}

void LYPineappleAction::issueLastHand(std::vector<LYCard> &cds,
		const std::string& table, const std::string& uid, unsigned int seat) {
	table_id = table;
	player = uid;
	applicant = seat;
	verb = LYCMD_ISSUE_LAST_HAND;
	setBricksByCards(cds);
}

void LYPineappleAction::pollingDecision(const std::string& table,
		unsigned int st) {
	table_id = table;
	verb = LYCMD_POLLING_DECISION;
	applicant = st;
	bricks.clear();
}

void LYPineappleAction::pinup(const std::string& table, unsigned int st,
		const std::vector<LYPineappleBrick>& bks) {
	table_id = table;
	verb = LYCMD_PINUP;
	applicant = st;
	bricks = bks;
}

void LYPineappleAction::issueHand(std::vector<LYCard>& cds,
		const std::string& table, const std::string& uid, unsigned int seat, unsigned int round) {
	switch (round) {
	case 1:
		issueFirstHand(cds, table, uid, seat);
		break;
	case 2:
		issueSecondHand(cds, table, uid, seat);
		break;
	case 3:
		issueThirdHand(cds, table, uid, seat);
		break;
	case 4:
		issueFouthHand(cds, table, uid, seat);
		break;
	case 5:
		issueLastHand(cds, table, uid, seat);
		break;
	default:
		break;
	}
}

std::string LYPineappleAction::stringOfBricks() {
	std::string sb;
	std::vector<LYPineappleBrick>::iterator it = bricks.begin();
	for (; it != bricks.end(); it++) {
		sb = sb + (*it).toString() + ",";
	}
	return sb;
}

std::string LYPineappleAction::sortedByFaceString()
{
	std::string sb;
	std::vector<LYCard> cards;
	std::vector<LYPineappleBrick>::iterator it = bricks.begin();
	for (; it!=bricks.end(); it++) {
		cards.push_back((*it).card);
	}
	LYCardHelpers::sortCardsByFace(cards);
	LYCardHelpers::cardsToStringifiedInt(cards, sb);
	return sb;
}

std::string LYPineappleAction::sortedBySuitString()
{
	std::string sb;
	std::vector<LYCard> cards;
	std::vector<LYPineappleBrick>::iterator it = bricks.begin();
	for (; it!=bricks.end(); it++) {
		cards.push_back((*it).card);
	}
	LYCardHelpers::sortCardsBySuit(cards);
	LYCardHelpers::cardsToStringifiedInt(cards, sb);
	return sb;
}

max_stars_repo_name: caiqingfeng/libpoker

max_issues_repo_name: caiqingfeng/libpoker

max_forks_repo_name: caiqingfeng/libpoker


text:
/* Copyright (C) 2017 IBM Corp.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
/*****************************************************************
 * test_CRTmatrix: a program for testing the CRTmatrix module
 *****************************************************************/
//#include <mpfr.h>
#include <NTL/lzz_p.h>

NTL_CLIENT
#include "../utils/argmap.h"
#include "../TDMatrix.h"

#if defined(__unix__) || defined(__unix) || defined(unix)
#include <sys/time.h>
#include <sys/resource.h>
#endif

#include <NTL/BasicThreadPool.h>

#define NFACTORS 8

long tinyFactors[NFACTORS] = { 2, 3, 5, 7, 11, 13, 17, 19 };

int main(int argc, char *argv[])
{
#ifdef DEBUG
    NTL::SetSeed((unsigned char*)"test_CRTmatrix",15);
#endif
    ArgMapping amap;
    long k = 3; //2
    amap.arg("k", k, "number of factors (~ log q)");
    long n = 5; //2
    amap.arg("n", n, "the small dimension");
    long e=3; //2
    amap.arg("e", e, "the power of each factor");
    long m=100; //0
    amap.arg("m", m, "the dimension m", "0: set as n*(2+k*e)");
    long threads = 2;
    amap.arg("threads", threads, "how many threads to run");

    amap.parse(argc, argv); // parses and overrides initail values
    // for each parameter, one per line,

    TDMatrixParams prms(n,k,e,m);
    m = prms.m;
    cout << "n="<<n<<", m="<<m<<", k="<<k<<", e="<<e<<", q="<<prms.getQ()
         << endl << endl;

    // Setup a htread pool with almost as many threads as there are cores
    if (threads<1) threads=1;
    else if (threads > numCores()-2) { // numCores() defined in utils/tools.h
      threads = numCores()-2;
      if (threads<1) threads=1;
    }
    NTL::SetNumThreads(threads);
    cout << "Using "<<threads<< " threads\n";

    CRTmatrix A(&prms);
    CRTmatrix B(&prms);
    CRTmatrix C(&prms);
    CRTmatrix I(&prms);
    CRTmatrix T1(&prms);
    CRTmatrix T2(&prms);
    CRTmatrix T3(&prms);
    CRTmatrix T4(&prms);

    generateMultiPair(A, B, prms.m);

    generateMatrixPair(A, B, n);
    C.invert(B);
    bool bTestRes = A==C;
    if (bTestRes==false)
    {
        cout << "Failed Generate Matrix Pair" << endl;
    }
    else
        cout << "Passed Generate Matrix Pair" << endl;

    bTestRes = A==A;

    if (bTestRes==false)
    {
        cout << "Failed Equality (==) Test" << endl;
    }
    else
         cout << "Passed Equality (==) Test" << endl;

    I.identity(n);

    //identity test

    bool bFailedIDTest = false;
    bool bFailedColumnTest = false;

    for (long lFactor=0; lFactor < prms.kFactors; lFactor++)
    {
        const mat_zz_p& aMod = I[lFactor];
        prms.zzp_context[lFactor].restore();

        for (long i = 0; i < n; i++)
        {
            CRTvector crtCol;
            I.getColumn(crtCol, i);
            for (long j = 0; j < n; j++)
            {
                if (i==j)
                {
                    if (aMod[i][j]!=1)
                    {
                        cout << "Failed Identity Test" << endl;
                        bFailedIDTest = true;
                    }
                    if (!IsOne(crtCol[lFactor][j]))
                    {
                        cout << "Failed Get Column Test" << endl;
                        bFailedColumnTest = true;
                    }
                }
                else
                {
                    if (aMod[i][j]!=0)
                    {
                        cout << "Failed Identity Test" << endl;
                        bFailedIDTest = true;
                    }
                    if (!IsZero(crtCol[lFactor][j]))
                    {
                        cout << "Failed Get Column Test" << endl;
                        bFailedColumnTest = true;
                    }
                }
            }
        }
    }

    if (bFailedIDTest == false)
        cout << "Passed Identity Test" << endl;
    if (bFailedColumnTest == false)
        cout << "Passed Get Column Test" << endl;

//cout << "A="<<A<<endl;
//cout << "I =" << I << endl;

// sanity-check
//    assert(A != I);

    A *= B;
    if (A == I) cout << "PASSED generate Matrix Pair\n";
    else        cout << "FAILED generate Matrix Pair\n";

    if (!(T1.NumCols() ==n))   //test NumCols()
        bTestRes = false;

    if (!(T1.NumRows() ==n))   //test NumRowls
        bTestRes = false;

    if (bTestRes==false)
        cout << "FAILED rows/cols num checking" << endl;
    else cout << "PASSED rows/cols num checking" << endl;

    mat_l longA;
    do
    {
        setSmall(longA, prms.n, prms.n, prms.r);
    }
    while (!B.invert(longA)); // Repeat until you get an invertible A mod q
    //cout << "longA=" << longA << "\n" << "B=" <<B << endl;

    A = B;

    B.leftMultBy(longA); //test left multiply by
    A *= longA; //test the *= multiplication

    if (A==I && B==I) cout << "PASSED create invertible matrix\n";
    else              cout << "FAILED create invertible matrix\n";

    T1.randomFill(prms.n,prms.n);
    //cout << "T1=" << T1 << endl;
    T2.randomFill(prms.n,prms.n);
    //cout << "T2=" << T2 << endl;
    // bool bIsSmall= T1.isSmall(prms.r);
    // bIsSmall= B.isSmall(prms.r);

    Vec<vec_zz_p> TestCol;
    B.getColumn(TestCol,1);
    //cout << TestCol << "\n";

    T3= T1;
    //cout << "T3=" << T3 << endl;
    //cout << "T1=" << T1 << endl;
    T1-=I;          //test -= multiplication
    T3-=I;

    //cout << "I=" << I << endl;
    //cout << "T1=" << T1 << endl;

    bool bPassedPMtests = true;

    if (!(T3==T1))
    {
        cout << "FAILED -= test" << endl;
        bPassedPMtests = false;
    }
    T1+=I;          //test += multiplication
    T3+=I;

    if (T3!=T1)
    {
        cout << "FAILED += test" << endl;
        bPassedPMtests = false;
    }
    //cout << "T1=" << T1 << ", T2=" << T2 << "\n";
    T1-=T2;
    //cout << "T1=" << T1 << "\n";
    T1+=T2;

    if (T3!=T1)
    {
        cout << "FAILED +=, -= tests" << endl;
        bPassedPMtests = false;
    }
    if (bPassedPMtests)
         cout << "PASSED +=, -= tests" << endl;

    FILE* handle = fopen("CRMatrixTest.dat", "wb");
    T2.writeToFile(handle);
    fclose(handle);

    handle = fopen("CRMatrixTest.dat", "rb");
    T4.readFromFile(handle,&prms);

    if (bTestRes)
        cout << "PASSED function test" << endl;
    else
        cout << "FAILED functions test" << endl;

   // cout << "T2=" << T2 << ", T4=" << T4 << endl;
    if (T2==T4)
        cout << "Read/Write Passed!" << endl;
    else
        cout << "Read/Write CRTmatrix failed" << endl;
    //assert(T2==T3);

    cout << "!"<< endl;
    printAllTimers(cout);

#ifdef CodeBlocks
    cin.get();
#endif
}

max_stars_repo_name: shaih/BPobfus

max_issues_repo_name: shaih/BPobfus

max_forks_repo_name: shaih/BPobfus


text:
/**
 * \file
 * \author Karsten Rink
 * \date   2013-04-04
 * \brief  Implementation of the MeshSurfaceExtraction class.
 *
 * \copyright
 * Copyright (c) 2012-2020, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 *
 */

#include "MeshSurfaceExtraction.h"

#include <boost/math/constants/constants.hpp>
#include "BaseLib/Logging.h"
#include <memory>

#include "MeshLib/Elements/Line.h"
#include "MeshLib/Elements/Point.h"
#include "MeshLib/Elements/Quad.h"
#include "MeshLib/Elements/Tri.h"
#include "MeshLib/Mesh.h"
#include "MeshLib/MeshEditing/DuplicateMeshComponents.h"
#include "MeshLib/MeshEditing/RemoveMeshComponents.h"
#include "MeshLib/MeshSearch/NodeSearch.h"

namespace MeshLib
{
template <typename T>
void processPropertyVector(MeshLib::PropertyVector<T> const& property,
                           std::vector<std::size_t> const& id_map,
                           MeshLib::Mesh& sfc_mesh)
{
    auto const number_of_components = property.getNumberOfGlobalComponents();

    auto sfc_prop = getOrCreateMeshProperty<T>(
        sfc_mesh, property.getPropertyName(), property.getMeshItemType(),
        number_of_components);
    sfc_prop->clear();
    sfc_prop->reserve(id_map.size());

    for (auto bulk_id : id_map)
    {
        std::copy_n(&property.getComponent(bulk_id, 0 /*component_id*/),
                    number_of_components, back_inserter(*sfc_prop));
    }
}

bool createSfcMeshProperties(MeshLib::Mesh& sfc_mesh,
                             MeshLib::Properties const& properties,
                             std::vector<std::size_t> const& node_ids_map,
                             std::vector<std::size_t> const& element_ids_map)
{
    std::size_t const n_elems(sfc_mesh.getNumberOfElements());
    std::size_t const n_nodes(sfc_mesh.getNumberOfNodes());
    if (node_ids_map.size() != n_nodes)
    {
        ERR("createSfcMeshProperties() - Incorrect number of node IDs ({:d}) "
            "compared to actual number of surface nodes ({:d}).",
            node_ids_map.size(), n_nodes);
        return false;
    }

    if (element_ids_map.size() != n_elems)
    {
        ERR("createSfcMeshProperties() - Incorrect number of element IDs "
            "({:d}) compared to actual number of surface elements ({:d}).",
            element_ids_map.size(), n_elems);
        return false;
    }
    std::map<MeshLib::MeshItemType, std::vector<std::size_t> const*> const
        id_maps = {{MeshItemType::Cell, &element_ids_map},
                   {MeshItemType::Node, &node_ids_map}};

    std::size_t vectors_copied(0);
    std::size_t vectors_skipped(0);
    for (auto [name, property] : properties)
    {
        if (property->getMeshItemType() != MeshItemType::Cell &&
            property->getMeshItemType() != MeshItemType::Node)
        {
            WARN(
                "Skipping property vector '{:s}' - not defined on cells or "
                "nodes.",
                name);
            vectors_skipped++;
            continue;
        }

        auto const& id_map = *id_maps.at(property->getMeshItemType());
        if (auto p = dynamic_cast<PropertyVector<double>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<float>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<int>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<unsigned>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<long>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<long long>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p =
                     dynamic_cast<PropertyVector<unsigned long>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<unsigned long long>*>(
                     property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<std::size_t>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else if (auto p = dynamic_cast<PropertyVector<char>*>(property))
        {
            processPropertyVector(*p, id_map, sfc_mesh);
            vectors_copied++;
        }
        else
        {
            WARN(
                "Skipping property vector '{:s}' - no matching data type '{:s}'"
                "found.",
                name, typeid(*property).name());
            vectors_skipped++;
        }
    }
    INFO("{:d} property vectors copied, {:d} vectors skipped.", vectors_copied,
         vectors_skipped);
    return true;
}

std::tuple<std::vector<MeshLib::Node*>, std::vector<std::size_t>>
createNodesAndIDMapFromElements(std::vector<MeshLib::Element*> const& elements,
                                std::size_t const n_all_nodes)
{
    std::vector<MeshLib::Node const*> tmp_nodes(n_all_nodes, nullptr);
    for (auto const* elem : elements)
    {
        auto const n_nodes = elem->getNumberOfNodes();
        for (unsigned j = 0; j < n_nodes; ++j)
        {
            const MeshLib::Node* node(elem->getNode(j));
            tmp_nodes[node->getID()] = node;
        }
    }

    std::vector<MeshLib::Node*> nodes;
    std::vector<std::size_t> node_id_map(n_all_nodes);
    for (unsigned i = 0; i < n_all_nodes; ++i)
    {
        if (tmp_nodes[i])
        {
            node_id_map[i] = nodes.size();
            nodes.push_back(new MeshLib::Node(*tmp_nodes[i]));
        }
    }
    return {nodes, node_id_map};
}

std::vector<double> MeshSurfaceExtraction::getSurfaceAreaForNodes(
    const MeshLib::Mesh& mesh)
{
    std::vector<double> node_area_vec;
    if (mesh.getDimension() != 2)
    {
        ERR("Error in MeshSurfaceExtraction::getSurfaceAreaForNodes() - Given "
            "mesh is no surface mesh (dimension != 2).");
        return node_area_vec;
    }

    double total_area(0);

    // for each node, a vector containing all the element idget every element
    const std::vector<MeshLib::Node*>& nodes = mesh.getNodes();
    const std::size_t nNodes(mesh.getNumberOfNodes());
    for (std::size_t n = 0; n < nNodes; ++n)
    {
        double node_area(0);

        std::vector<MeshLib::Element*> conn_elems = nodes[n]->getElements();
        const std::size_t nConnElems(conn_elems.size());

        for (std::size_t i = 0; i < nConnElems; ++i)
        {
            const MeshLib::Element* elem(conn_elems[i]);
            const unsigned nElemParts =
                (elem->getGeomType() == MeshElemType::TRIANGLE) ? 3 : 4;
            const double area = conn_elems[i]->getContent() / nElemParts;
            node_area += area;
            total_area += area;
        }

        node_area_vec.push_back(node_area);
    }

    INFO("Total surface Area: {:f}", total_area);

    return node_area_vec;
}

MeshLib::Mesh* MeshSurfaceExtraction::getMeshSurface(
    const MeshLib::Mesh& subsfc_mesh, const MathLib::Vector3& dir, double angle,
    std::string const& subsfc_node_id_prop_name,
    std::string const& subsfc_element_id_prop_name,
    std::string const& face_id_prop_name)
{
    // allow slightly greater angles than 90 degrees for numerical errors
    if (angle < 0 || angle > 91)
    {
        ERR("Supported angle between 0 and 90 degrees only.");
        return nullptr;
    }

    INFO("Extracting mesh surface...");
    std::vector<MeshLib::Element*> sfc_elements;
    std::vector<std::size_t> element_ids_map;
    std::vector<std::size_t> face_ids_map;
    get2DSurfaceElements(subsfc_mesh.getElements(), sfc_elements,
                         element_ids_map, face_ids_map, dir, angle,
                         subsfc_mesh.getDimension());

    if (sfc_elements.empty())
    {
        return nullptr;
    }

    auto [sfc_nodes, node_id_map] = createNodesAndIDMapFromElements(
        sfc_elements, subsfc_mesh.getNumberOfNodes());

    // create new elements vector with newly created nodes (and delete
    // temp-elements)
    auto new_elements =
        MeshLib::copyElementVector(sfc_elements, sfc_nodes, &node_id_map);
    std::for_each(sfc_elements.begin(), sfc_elements.end(),
                  [](MeshLib::Element* e) { delete e; });

    std::vector<std::size_t> id_map;
    id_map.reserve(sfc_nodes.size());
    std::transform(begin(sfc_nodes), end(sfc_nodes), std::back_inserter(id_map),
                   [](MeshLib::Node* const n) { return n->getID(); });

    MeshLib::Mesh* result(
        new Mesh(subsfc_mesh.getName() + "-Surface", sfc_nodes, new_elements));

    addBulkIDPropertiesToMesh(*result, subsfc_node_id_prop_name, id_map,
                              subsfc_element_id_prop_name, element_ids_map,
                              face_id_prop_name, face_ids_map);

    if (!createSfcMeshProperties(*result, subsfc_mesh.getProperties(), id_map,
                                 element_ids_map))
    {
        ERR("Transferring subsurface properties failed.");
    }
    return result;
}

void MeshSurfaceExtraction::get2DSurfaceElements(
    const std::vector<MeshLib::Element*>& all_elements,
    std::vector<MeshLib::Element*>& sfc_elements,
    std::vector<std::size_t>& element_to_bulk_element_id_map,
    std::vector<std::size_t>& element_to_bulk_face_id_map,
    const MathLib::Vector3& dir, double angle, unsigned mesh_dimension)
{
    if (mesh_dimension < 2 || mesh_dimension > 3)
    {
        ERR("Cannot handle meshes of dimension {:i}", mesh_dimension);
    }

    bool const complete_surface = (MathLib::scalarProduct(dir, dir) == 0);

    double const pi(boost::math::constants::pi<double>());
    double const cos_theta(std::cos(angle * pi / 180.0));
    MathLib::Vector3 const norm_dir(dir.getNormalizedVector());

    for (auto const* elem : all_elements)
    {
        const unsigned element_dimension(elem->getDimension());
        if (element_dimension < mesh_dimension)
        {
            continue;
        }

        if (element_dimension == 2)
        {
            if (!complete_surface)
            {
                auto const* face = elem;
                if (MathLib::scalarProduct(
                        FaceRule::getSurfaceNormal(face).getNormalizedVector(),
                        norm_dir) > cos_theta)
                {
                    continue;
                }
            }
            sfc_elements.push_back(elem->clone());
            element_to_bulk_element_id_map.push_back(elem->getID());
            element_to_bulk_face_id_map.push_back(0);
        }
        else
        {
            if (!elem->isBoundaryElement())
            {
                continue;
            }
            const unsigned nFaces(elem->getNumberOfFaces());
            for (unsigned j = 0; j < nFaces; ++j)
            {
                if (elem->getNeighbor(j) != nullptr)
                {
                    continue;
                }

                auto const face =
                    std::unique_ptr<MeshLib::Element const>{elem->getFace(j)};
                if (!complete_surface)
                {
                    if (MathLib::scalarProduct(
                            FaceRule::getSurfaceNormal(face.get())
                                .getNormalizedVector(),
                            norm_dir) < cos_theta)
                    {
                        continue;
                    }
                }
                if (face->getGeomType() == MeshElemType::TRIANGLE)
                {
                    sfc_elements.push_back(new MeshLib::Tri(
                        *static_cast<const MeshLib::Tri*>(face.get())));
                }
                else
                {
                    sfc_elements.push_back(new MeshLib::Quad(
                        *static_cast<const MeshLib::Quad*>(face.get())));
                }
                element_to_bulk_element_id_map.push_back(elem->getID());
                element_to_bulk_face_id_map.push_back(j);
            }
        }
    }
}

std::vector<MeshLib::Node*> MeshSurfaceExtraction::getSurfaceNodes(
    const MeshLib::Mesh& mesh, const MathLib::Vector3& dir, double angle)
{
    INFO("Extracting surface nodes...");
    std::vector<MeshLib::Element*> sfc_elements;
    std::vector<std::size_t> element_to_bulk_element_id_map;
    std::vector<std::size_t> element_to_bulk_face_id_map;
    get2DSurfaceElements(
        mesh.getElements(), sfc_elements, element_to_bulk_element_id_map,
        element_to_bulk_face_id_map, dir, angle, mesh.getDimension());

    std::vector<MeshLib::Node*> surface_nodes;
    std::tie(surface_nodes, std::ignore) =
        createNodesAndIDMapFromElements(sfc_elements, mesh.getNumberOfNodes());

    for (auto e : sfc_elements)
    {
        delete e;
    }

    return surface_nodes;
}

void createSurfaceElementsFromElement(
    MeshLib::Element const& surface_element,
    std::vector<MeshLib::Element*>& surface_elements,
    std::vector<std::size_t>& element_to_bulk_element_id_map,
    std::vector<std::size_t>& element_to_bulk_face_id_map)
{
    const unsigned n_faces(surface_element.getNumberOfBoundaries());
    for (unsigned j = 0; j < n_faces; ++j)
    {
        if (surface_element.getNeighbor(j) != nullptr)
        {
            continue;
        }

        surface_elements.push_back(
            const_cast<MeshLib::Element*>(surface_element.getBoundary(j)));
        element_to_bulk_face_id_map.push_back(j);
        element_to_bulk_element_id_map.push_back(surface_element.getID());
    }
}

std::tuple<std::vector<MeshLib::Element*>, std::vector<std::size_t>,
           std::vector<std::size_t>>
createBoundaryElements(MeshLib::Mesh const& bulk_mesh)
{
    std::vector<std::size_t> element_to_bulk_element_id_map;
    std::vector<std::size_t> element_to_bulk_face_id_map;
    std::vector<MeshLib::Element*> surface_elements;

    auto const& bulk_elements = bulk_mesh.getElements();
    auto const mesh_dimension = bulk_mesh.getDimension();

    for (auto const* elem : bulk_elements)
    {
        const unsigned element_dimension(elem->getDimension());
        if (element_dimension < mesh_dimension)
        {
            continue;
        }

        if (!elem->isBoundaryElement())
        {
            continue;
        }
        createSurfaceElementsFromElement(*elem, surface_elements,
                                         element_to_bulk_element_id_map,
                                         element_to_bulk_face_id_map);
    }
    return {surface_elements, element_to_bulk_element_id_map,
            element_to_bulk_face_id_map};
}

namespace BoundaryExtraction
{
std::unique_ptr<MeshLib::Mesh> getBoundaryElementsAsMesh(
    MeshLib::Mesh const& bulk_mesh,
    std::string const& subsfc_node_id_prop_name,
    std::string const& subsfc_element_id_prop_name,
    std::string const& face_id_prop_name)
{
    auto const mesh_dimension = bulk_mesh.getDimension();
    if (mesh_dimension < 2 || mesh_dimension > 3)
    {
        ERR("Cannot handle meshes of dimension {:i}", mesh_dimension);
    }

    // create boundary elements based on the subsurface nodes
    auto [boundary_elements, element_to_bulk_element_id_map,
          element_to_bulk_face_id_map] = createBoundaryElements(bulk_mesh);

    // create new nodes needed for the new surface elements
    auto [boundary_nodes, node_id_map] = createNodesAndIDMapFromElements(
        boundary_elements, bulk_mesh.getNumberOfNodes());

    // create new elements using newly created nodes and delete temp-elements
    auto new_elements = MeshLib::copyElementVector(
        boundary_elements, boundary_nodes, &node_id_map);
    for (auto* e : boundary_elements)
    {
        delete e;
    }

    std::vector<std::size_t> nodes_to_bulk_nodes_id_map;
    nodes_to_bulk_nodes_id_map.reserve(boundary_nodes.size());
    std::transform(begin(boundary_nodes), end(boundary_nodes),
                   std::back_inserter(nodes_to_bulk_nodes_id_map),
                   [](MeshLib::Node* const n) { return n->getID(); });

    std::unique_ptr<MeshLib::Mesh> boundary_mesh(new Mesh(
        bulk_mesh.getName() + "-boundary", boundary_nodes, new_elements));

    addBulkIDPropertiesToMesh(
        *boundary_mesh, subsfc_node_id_prop_name, nodes_to_bulk_nodes_id_map,
        subsfc_element_id_prop_name, element_to_bulk_element_id_map,
        face_id_prop_name, element_to_bulk_face_id_map);

    /// Copies relevant parts of scalar arrays to the surface mesh
    if (!createSfcMeshProperties(*boundary_mesh, bulk_mesh.getProperties(),
                                 nodes_to_bulk_nodes_id_map,
                                 element_to_bulk_element_id_map))
    {
        ERR("Transferring subsurface properties failed.");
    }
    return boundary_mesh;
}

}  // namespace BoundaryExtraction

void addBulkIDPropertiesToMesh(
    MeshLib::Mesh& surface_mesh,
    std::string const& node_to_bulk_node_id_map_name,
    std::vector<std::size_t> const& node_to_bulk_node_id_map,
    std::string const& element_to_bulk_element_id_map_name,
    std::vector<std::size_t> const& element_to_bulk_element_id_map,
    std::string const& element_to_bulk_face_id_map_name,
    std::vector<std::size_t> const& element_to_bulk_face_id_map)
{
    // transmit the original node ids of the bulk mesh as a property
    if (!node_to_bulk_node_id_map_name.empty())
    {
        MeshLib::addPropertyToMesh(surface_mesh, node_to_bulk_node_id_map_name,
                                   MeshLib::MeshItemType::Node, 1,
                                   node_to_bulk_node_id_map);
    }

    // transmit the original bulk element ids as a property
    if (!element_to_bulk_element_id_map_name.empty())
    {
        MeshLib::addPropertyToMesh(
            surface_mesh, element_to_bulk_element_id_map_name,
            MeshLib::MeshItemType::Cell, 1, element_to_bulk_element_id_map);
    }

    // transmit the face id of the original bulk element as a property
    if (!element_to_bulk_face_id_map_name.empty())
    {
        MeshLib::addPropertyToMesh(
            surface_mesh, element_to_bulk_face_id_map_name,
            MeshLib::MeshItemType::Cell, 1, element_to_bulk_face_id_map);
    }
}

}  // end namespace MeshLib

max_stars_repo_name: yezhigangzju/ogs

max_issues_repo_name: yezhigangzju/ogs

max_forks_repo_name: yezhigangzju/ogs