text:
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Framework/TestingFramework.hpp"

#include <algorithm>
#include <boost/iterator/transform_iterator.hpp>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>

#include "DataStructures/DataVector.hpp"
#include "DataStructures/Tensor/TensorData.hpp"
#include "IO/H5/AccessType.hpp"
#include "IO/H5/File.hpp"
#include "IO/H5/VolumeData.hpp"
#include "NumericalAlgorithms/Spectral/Spectral.hpp"
#include "Utilities/Algorithm.hpp"
#include "Utilities/ErrorHandling/Error.hpp"
#include "Utilities/FileSystem.hpp"
#include "Utilities/MakeString.hpp"
#include "Utilities/Numeric.hpp"

namespace {
template <typename T>
T multiply(const double obs_value, const T& component) {
  T result = component;
  for (auto& t : result) {
    t *= obs_value;
  }
  return result;
}

template <typename DataType>
void test() {
  const std::string h5_file_name("Unit.IO.H5.VolumeData.h5");
  const uint32_t version_number = 4;
  if (file_system::check_if_file_exists(h5_file_name)) {
    file_system::rm(h5_file_name, true);
  }

  h5::H5File<h5::AccessType::ReadWrite> my_file(h5_file_name);
  const std::vector<DataType> tensor_components_and_coords{
      {8.9, 7.6, 3.9, 2.1, 18.9, 17.6, 13.9, 12.1},
      {0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0},
      {0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0},
      {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0},
      {-78.9, -7.6, -1.9, 8.1, 6.3, 8.7, 9.8, 0.2},
      {-7.9, 7.6, 1.9, -8.1, -6.3, 2.7, 6.8, -0.2},
      {17.9, 27.6, 21.9, -28.1, -26.3, 32.7, 26.8, -30.2}};
  const std::vector<size_t> observation_ids{8435087234, size_t(-1)};
  const std::vector<double> observation_values{8.0, 2.3};
  const std::vector<std::string> grid_names{"[[2,3,4]]", "[[5,6,7]]"};
  const std::vector<std::vector<Spectral::Basis>> bases{
      {3, Spectral::Basis::Chebyshev}, {3, Spectral::Basis::Legendre}};
  const std::vector<std::vector<Spectral::Quadrature>> quadratures{
      {3, Spectral::Quadrature::Gauss},
      {3, Spectral::Quadrature::GaussLobatto}};
  {
    auto& volume_file =
        my_file.insert<h5::VolumeData>("/element_data", version_number);
    const auto write_to_file = [&volume_file, &tensor_components_and_coords,
                                &grid_names, &bases,
                                &quadratures](const size_t observation_id,
                                              const double observation_value) {
      std::string first_grid = grid_names.front();
      std::string last_grid = grid_names.back();
      volume_file.write_volume_data(
          observation_id, observation_value,
          std::vector<ElementVolumeData>{
              {{2, 2, 2},
               {TensorComponent{first_grid + "/S",
                                multiply(observation_value,
                                         tensor_components_and_coords[0])},
                TensorComponent{first_grid + "/x-coord",
                                multiply(observation_value,
                                         tensor_components_and_coords[1])},
                TensorComponent{first_grid + "/y-coord",
                                multiply(observation_value,
                                         tensor_components_and_coords[2])},
                TensorComponent{first_grid + "/z-coord",
                                multiply(observation_value,
                                         tensor_components_and_coords[3])},
                TensorComponent{first_grid + "/T_x",
                                multiply(observation_value,
                                         tensor_components_and_coords[4])},
                TensorComponent{first_grid + "/T_y",
                                multiply(observation_value,
                                         tensor_components_and_coords[5])},
                TensorComponent{first_grid + "/T_z",
                                multiply(observation_value,
                                         tensor_components_and_coords[6])}},
               bases.front(),
               quadratures.front()},
              // Second Element Data
              {{2, 2, 2},
               {TensorComponent{last_grid + "/S",
                                multiply(observation_value,
                                         tensor_components_and_coords[1])},
                TensorComponent{last_grid + "/x-coord",
                                multiply(observation_value,
                                         tensor_components_and_coords[0])},
                TensorComponent{last_grid + "/y-coord",
                                multiply(observation_value,
                                         tensor_components_and_coords[5])},
                TensorComponent{last_grid + "/z-coord",
                                multiply(observation_value,
                                         tensor_components_and_coords[3])},
                TensorComponent{last_grid + "/T_x",
                                multiply(observation_value,
                                         tensor_components_and_coords[6])},
                TensorComponent{last_grid + "/T_y",
                                multiply(observation_value,
                                         tensor_components_and_coords[4])},
                TensorComponent{last_grid + "/T_z",
                                multiply(observation_value,
                                         tensor_components_and_coords[2])}},
               bases.back(),
               quadratures.back()}});
    };
    for (size_t i = 0; i < observation_ids.size(); ++i) {
      write_to_file(observation_ids[i], observation_values[i]);
    }
  }
  // Open the read volume file and check that the observation id and values are
  // correct.
  const auto& volume_file =
      my_file.get<h5::VolumeData>("/element_data", version_number);
  const auto read_observation_ids = volume_file.list_observation_ids();
  CHECK(alg::all_of(read_observation_ids, [&observation_ids](const size_t id) {
    return alg::found(observation_ids, id);
  }));
  {
    INFO("Test find_observation_id");
    std::vector<size_t> found_observation_ids(observation_values.size());
    std::transform(observation_values.begin(), observation_values.end(),
                   found_observation_ids.begin(),
                   [&volume_file](const double observation_value) {
                     return volume_file.find_observation_id(observation_value);
                   });
    CHECK(found_observation_ids == observation_ids);
  }
  // Check that the volume data is correct
  const auto check_time = [&volume_file, &tensor_components_and_coords,
                           &grid_names, &bases,
                           &quadratures](const size_t observation_id,
                                         const double observation_value) {
    CHECK(std::vector<std::vector<size_t>>{{2, 2, 2}, {2, 2, 2}} ==
          volume_file.get_extents(observation_id));
    CHECK(volume_file.get_observation_value(observation_id) ==
          observation_value);
    // Check that all of the grid names were written correctly by checking their
    // equality of elements
    const std::vector<std::string> read_grid_names =
        volume_file.get_grid_names(observation_id);
    [&read_grid_names, &grid_names]() {
      auto sortable_grid_names = grid_names;
      auto sortable_read_grid_names = read_grid_names;
      std::sort(sortable_grid_names.begin(), sortable_grid_names.end(),
                std::less<>{});
      std::sort(sortable_read_grid_names.begin(),
                sortable_read_grid_names.end(), std::less<>{});
      REQUIRE(sortable_read_grid_names == sortable_grid_names);
    }();
    // Find the order the grids were written in
    std::vector<size_t> grid_positions(read_grid_names.size());
    for (size_t i = 0; i < grid_positions.size(); i++) {
      auto grid_name = grid_names[i];
      auto position =
          std::find(read_grid_names.begin(), read_grid_names.end(), grid_name);
      // We know the grid name is in the read_grid_names because of the previous
      // so we know `position` is an actual pointer to an element
      grid_positions[i] =
          static_cast<size_t>(std::distance(read_grid_names.begin(), position));
    }
    auto read_bases = volume_file.get_bases(observation_id);
    alg::sort(read_bases, std::less<>{});
    auto read_quadratures = volume_file.get_quadratures(observation_id);
    alg::sort(read_quadratures, std::less<>{});
    // We need non-const bases and quadratures in order to sort them, and we
    // need them in their string form,
    const auto& stringify = [](const auto& bases_or_quadratures) {
      std::vector<std::vector<std::string>> local_target_data{};
      local_target_data.reserve(bases_or_quadratures.size() + 1);
      for (const auto& element_data : bases_or_quadratures) {
        std::vector<std::string> target_axis_data{};
        target_axis_data.reserve(element_data.size() + 1);
        for (const auto& axis_datum : element_data) {
          target_axis_data.emplace_back(MakeString{} << axis_datum);
        }
        local_target_data.push_back(target_axis_data);
      }
      return local_target_data;
    };
    auto target_bases = stringify(bases);
    alg::sort(target_bases, std::less<>{});
    auto target_quadratures = stringify(quadratures);
    alg::sort(target_quadratures, std::less<>{});
    CHECK(target_bases == read_bases);
    CHECK(target_quadratures == read_quadratures);
    const std::vector<std::string> expected_components{
        "S", "x-coord", "y-coord", "z-coord", "T_x", "T_y", "T_z",
    };
    const auto read_components =
        volume_file.list_tensor_components(observation_id);
    CHECK(alg::all_of(read_components,
                      [&expected_components](const std::string& id) {
                        return alg::found(expected_components, id);
                      }));
    // Helper Function to get number of points on a particular grid
    const auto accumulate_extents =
        [](const std::vector<size_t>& grid_extents) {
          return alg::accumulate(grid_extents, 1, std::multiplies<>{});
        };

    const auto read_extents = volume_file.get_extents(observation_id);
    std::vector<size_t> element_num_points(
        boost::make_transform_iterator(read_extents.begin(),
                                       accumulate_extents),
        boost::make_transform_iterator(read_extents.end(), accumulate_extents));
    const auto read_points_by_element = [&element_num_points]() {
      std::vector<size_t> read_points(element_num_points.size());
      read_points[0] = 0;
      for (size_t index = 1; index < element_num_points.size(); index++) {
        read_points[index] =
            read_points[index - 1] + element_num_points[index - 1];
      }
      return read_points;
    }();
    // Given a DataType, corresponding to contiguous data read out of a
    // file, find the data which was written by the grid whose extents are
    // found at position `grid_index` in the vector of extents.
    const auto get_grid_data = [&element_num_points, &read_points_by_element](
                                   const DataVector& all_data,
                                   const size_t grid_index) {
      DataType result(element_num_points[grid_index]);
      // clang-tidy: do not use pointer arithmetic
      std::copy(&all_data[read_points_by_element[grid_index]],
                &all_data[read_points_by_element[grid_index]] +  // NOLINT
                    element_num_points[grid_index],
                result.begin());
      return result;
    };
    // The order the fake tensor data was assigned to the tensor components
    std::vector<std::vector<size_t>> grid_data_orders{{0, 1, 2, 3, 4, 5, 6},
                                                      {1, 0, 5, 3, 6, 4, 2}};
    // The tensor components can be written in any order to the file, we loop
    // over the expected components rather than the read components because they
    // are in a particular order.
    for (size_t i = 0; i < expected_components.size(); i++) {
      const auto& component = expected_components[i];
      // for each grid
      for (size_t j = 0; j < grid_names.size(); j++) {
        CHECK(get_grid_data(
                  volume_file.get_tensor_component(observation_id, component),
                  grid_positions[j]) ==
              multiply(observation_value,
                       tensor_components_and_coords[grid_data_orders[j][i]]));
      }
    }
  };
  for (size_t i = 0; i < observation_ids.size(); ++i) {
    check_time(observation_ids[i], observation_values[i]);
  }

  {
    INFO("offset_and_length_for_grid");
    const size_t observation_id = observation_ids.front();
    // [find_offset]
    const auto all_grid_names = volume_file.get_grid_names(observation_id);
    const auto all_extents = volume_file.get_extents(observation_id);
    const auto first_grid_offset_and_length = h5::offset_and_length_for_grid(
        grid_names.front(), all_grid_names, all_extents);
    // [find_offset]
    CHECK(first_grid_offset_and_length.first == 0);
    CHECK(first_grid_offset_and_length.second == 8);
    const auto last_grid_offset_and_length = h5::offset_and_length_for_grid(
        grid_names.back(), all_grid_names, all_extents);
    CHECK(last_grid_offset_and_length.first == 8);
    CHECK(last_grid_offset_and_length.second == 8);
  }

  if (file_system::check_if_file_exists(h5_file_name)) {
    file_system::rm(h5_file_name, true);
  }
}
}  // namespace

SPECTRE_TEST_CASE("Unit.IO.H5.VolumeData", "[Unit][IO][H5]") {
  test<DataVector>();
  test<std::vector<float>>();
}

// [[OutputRegex, The expected format of the tensor component names is
// 'GROUP_NAME/COMPONENT_NAME' but could not find a '/' in]]
[[noreturn]] SPECTRE_TEST_CASE("Unit.IO.H5.VolumeData.ComponentFormat0",
                               "[Unit][IO][H5]") {
  ASSERTION_TEST();
#ifdef SPECTRE_DEBUG
  const std::string h5_file_name("Unit.IO.H5.VolumeData.ComponentFormat.h5");
  const uint32_t version_number = 4;
  if (file_system::check_if_file_exists(h5_file_name)) {
    file_system::rm(h5_file_name, true);
  }
  h5::H5File<h5::AccessType::ReadWrite> my_file(h5_file_name);
  auto& volume_file =
      my_file.insert<h5::VolumeData>("/element_data", version_number);
  volume_file.write_volume_data(100, 10.0,
                                {{{2},
                                  {TensorComponent{"S", DataVector{1.0, 2.0}}},
                                  {Spectral::Basis::Legendre},
                                  {Spectral::Quadrature::Gauss}}});
  ERROR("Failed to trigger ASSERT in an assertion test");
#endif
  // clang-format off
}

// [[OutputRegex, The expected format of the tensor component names is
// 'GROUP_NAME/COMPONENT_NAME' but could not find a '/' in]]
[[noreturn]]
SPECTRE_TEST_CASE("Unit.IO.H5.VolumeData.ComponentFormat1",
                               "[Unit][IO][H5]") {
  // clang-format on
  ASSERTION_TEST();
#ifdef SPECTRE_DEBUG
  const std::string h5_file_name("Unit.IO.H5.VolumeData.ComponentFormat1.h5");
  const uint32_t version_number = 4;
  if (file_system::check_if_file_exists(h5_file_name)) {
    file_system::rm(h5_file_name, true);
  }
  h5::H5File<h5::AccessType::ReadWrite> my_file(h5_file_name);
  auto& volume_file =
      my_file.insert<h5::VolumeData>("/element_data", version_number);
  volume_file.write_volume_data(100, 10.0,
                                {{{2},
                                  {TensorComponent{"A/S", DataVector{1.0, 2.0}},
                                   TensorComponent{"S", DataVector{1.0, 2.0}}},
                                  {Spectral::Basis::Legendre},
                                  {Spectral::Quadrature::Gauss}}});
  ERROR("Failed to trigger ASSERT in an assertion test");
#endif
  // clang-format off
}

// [[OutputRegex, Trying to write tensor component 'S' which already exists
// in HDF5 file in group 'element_data.vol/ObservationId100']]
[[noreturn]] SPECTRE_TEST_CASE("Unit.IO.H5.VolumeData.WriteTwice",
                               "[Unit][IO][H5]") {
  // clang-format on
  ASSERTION_TEST();
#ifdef SPECTRE_DEBUG
  const std::string h5_file_name("Unit.IO.H5.VolumeData.WriteTwice.h5");
  const uint32_t version_number = 4;
  if (file_system::check_if_file_exists(h5_file_name)) {
    file_system::rm(h5_file_name, true);
  }
  h5::H5File<h5::AccessType::ReadWrite> my_file(h5_file_name);
  auto& volume_file =
      my_file.insert<h5::VolumeData>("/element_data", version_number);
  volume_file.write_volume_data(
      100, 10.0,
      {{{2},
        {TensorComponent{"A/S", DataVector{1.0, 2.0}},
         TensorComponent{"A/S", DataVector{1.0, 2.0}}},
        {Spectral::Basis::Legendre},
        {Spectral::Quadrature::Gauss}}});
  ERROR("Failed to trigger ASSERT in an assertion test");
#endif
  // clang-format off
}

// [[OutputRegex, No observation with value]]
SPECTRE_TEST_CASE("Unit.IO.H5.VolumeData.FindNoObservationId",
                  "[Unit][IO][H5]") {
  // clang-format on
  ERROR_TEST();
  const std::string h5_file_name(
      "Unit.IO.H5.VolumeData.FindNoObservationId.h5");
  const uint32_t version_number = 4;
  if (file_system::check_if_file_exists(h5_file_name)) {
    file_system::rm(h5_file_name, true);
  }
  h5::H5File<h5::AccessType::ReadWrite> h5_file(h5_file_name);
  auto& volume_file =
      h5_file.insert<h5::VolumeData>("/element_data", version_number);
  volume_file.write_volume_data(
      100, 10.0,
      {{{2},
        {TensorComponent{"A/S", DataVector{1.0, 2.0}}},
        {Spectral::Basis::Legendre},
        {Spectral::Quadrature::Gauss}}});
  volume_file.find_observation_id(11.0);
}

max_stars_repo_name: kidder/spectre

max_issues_repo_name: GitHimanshuc/spectre


text:
#include "test/compression_unittest_base.hpp"
#include "scale_encoding.hpp"
#include <gtest/gtest.h>
#include <boost/bind.hpp>

namespace ddj {

class ScaleCompressionTest : public CompressionUnittestBase {};

INSTANTIATE_TEST_CASE_P(
    ScaleEncoding_Compression_Inst,
    ScaleCompressionTest,
    ::testing::Values(100, 100000));

TEST_P(ScaleCompressionTest, CompressionOfRandomInts_size)
{
    ScaleEncoding encoder;
    EXPECT_TRUE(
		TestSize<int>(
			boost::bind(&ScaleEncoding::Encode<int>, encoder, _1),
			boost::bind(&ScaleEncoding::Decode<int>, encoder, _1),
			GetIntRandomData())
    );
}

TEST_P(ScaleCompressionTest, CompressionOfRandomInts_data)
{
	ScaleEncoding encoder;
	EXPECT_TRUE(
		TestContent<int>(
			boost::bind(&ScaleEncoding::Encode<int>, encoder, _1),
			boost::bind(&ScaleEncoding::Decode<int>, encoder, _1),
			GetIntRandomData())
	);
}

TEST_P(ScaleCompressionTest, CompressionOfRandomFloats_size)
{
    ScaleEncoding encoder;
    EXPECT_TRUE(
		TestSize<float>(
			boost::bind(&ScaleEncoding::Encode<float>, encoder, _1),
			boost::bind(&ScaleEncoding::Decode<float>, encoder, _1),
			GetFloatRandomData())
    );
}

TEST_P(ScaleCompressionTest, CompressionOfRandomFloats_data)
{
	ScaleEncoding encoder;
	EXPECT_TRUE(
		TestContent<float>(
			boost::bind(&ScaleEncoding::Encode<float>, encoder, _1),
			boost::bind(&ScaleEncoding::Decode<float>, encoder, _1),
			GetFloatRandomData())
	);
}

TEST_P(ScaleCompressionTest, CompressionOf_PatternA_Short)
{
	ScaleEncoding encoder;
	EXPECT_TRUE(
		TestContent<short>(
			boost::bind(&ScaleEncoding::Encode<short>, encoder, _1),
			boost::bind(&ScaleEncoding::Decode<short>, encoder, _1),
			GetFakeDataWithPatternA<short>(0, GetSize()/3, 1, 0, 1e3))
	);
}

TEST_P(ScaleCompressionTest, CompressionOf_PatternA_Char)
{
	ScaleEncoding encoder;
	EXPECT_TRUE(
		TestContent<char>(
			boost::bind(&ScaleEncoding::Encode<char>, encoder, _1),
			boost::bind(&ScaleEncoding::Decode<char>, encoder, _1),
			GetFakeDataWithPatternA<char>(0, GetSize()/3, 1, 0, 1e2))
	);
}

TEST_P(ScaleCompressionTest, GetMetadataSize_Consecutive_Int)
{
	TestGetMetadataSize<ScaleEncoding, int>(GetIntConsecutiveData());
	TestGetMetadataSize<ScaleEncoding, float>(GetFloatRandomDataWithMaxPrecision(2));
}

TEST_P(ScaleCompressionTest, GetCompressedSize_Consecutive_Int)
{
	TestGetCompressedSize<ScaleEncoding, int>(GetIntConsecutiveData());
	TestGetCompressedSize<ScaleEncoding, float>(GetFloatRandomDataWithMaxPrecision(2));
}

} /* namespace ddj */

ext: cpp

max_stars_repo_licenses: MIT Unlicense

max_issues_repo_licenses: MIT Unlicense

max_forks_repo_licenses: MIT Unlicense


text:
//
// Copyright 2016 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
//    names, trademarks, service marks, or product names of the Licensor
//    and its affiliates, except as required to comply with Section 4(c) of
//    the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#include "pxr/pxr.h"
#include "pxr/base/arch/attributes.h"
#include "pxr/base/arch/stackTrace.h"
#include "pxr/base/arch/vsnprintf.h"
#include "pxr/base/tf/ostreamMethods.h"
#include "pxr/base/tf/patternMatcher.h"
#include "pxr/base/tf/stringUtils.h"
#include "pxr/base/tf/scopeDescription.h"
#include "pxr/usd/sdf/layer.h"

#include <boost/program_options.hpp>

#include <cstdio>
#include <cstdarg>
#include <iostream>
#include <string>
#include <utility>
#include <unordered_map>
#include <unordered_set>
#include <vector>

PXR_NAMESPACE_OPEN_SCOPE

using std::string;
using std::vector;
using std::ostream;
using std::pair;
using std::unordered_map;
using std::unordered_set;

namespace {

string progName;

void VErr(char const *fmt, va_list ap) {
    fprintf(stderr, "%s: Error - %s\n", progName.c_str(),
            ArchVStringPrintf(fmt, ap).c_str());
}

void VPrint(char const *fmt, va_list ap) { vprintf(fmt, ap); }

void Err(char const *fmt, ...) ARCH_PRINTF_FUNCTION(1, 2);
void Err(char const *fmt, ...) {
    va_list ap; va_start(ap, fmt); VErr(fmt, ap); va_end(ap);
}

void ErrExit(char const *fmt, ...) ARCH_PRINTF_FUNCTION(1, 2);
void ErrExit(char const *fmt, ...) {
    va_list ap; va_start(ap, fmt); VErr(fmt, ap); va_end(ap);
    exit(1);
}

void Print(char const *fmt, ...) ARCH_PRINTF_FUNCTION(1, 2);
void Print(char const *fmt, ...) {
    va_list ap; va_start(ap, fmt); VPrint(fmt, ap); va_end(ap);
}

bool IsClose(double a, double b, double tol)
{
    double absDiff = fabs(a-b);
    return absDiff <= fabs(tol*a) || absDiff < fabs(tol*b);
}

struct SortKey {
    SortKey() : key("path") {}
    SortKey(string key) : key(key) {}
    string key;
};
ostream &operator<<(ostream &os, SortKey const &sk) { return os << sk.key; }

// boost::program_options calls validate() for custom argument types.
void validate(boost::any& v, const vector<string> &values, SortKey*, int) {
    using namespace boost::program_options;
    validators::check_first_occurrence(v);
    string const &s = validators::get_single_string(values);
    if (s == "path" || s == "field") {
        v = SortKey(s);
    } else {
        throw validation_error(validation_error::invalid_option_value);
    }
}

// Parse times and time ranges in timeSpecs, throw an exception if something
// goes wrong.
void
ParseTimes(vector<string> const &timeSpecs,
           vector<double> *literalTimes,
           vector<pair<double, double>> *timeRanges)
{
    for (auto const &spec: timeSpecs) {
        try {
            if (TfStringContains(spec, "..")) {
                auto elts = TfStringSplit(spec, "..");
                if (elts.size() != 2) {
                    throw std::invalid_argument(
                        TfStringPrintf("invalid time syntax '%s'",
                                       spec.c_str()));
                }
                timeRanges->emplace_back(boost::lexical_cast<double>(elts[0]),
                                         boost::lexical_cast<double>(elts[1]));
            } else {
                literalTimes->emplace_back(boost::lexical_cast<double>(spec));
            }
        } catch (boost::bad_lexical_cast const &) {
            throw std::invalid_argument(
                TfStringPrintf("invalid time syntax '%s'", spec.c_str()));
        }
    }
    sort(literalTimes->begin(), literalTimes->end());
    literalTimes->erase(unique(literalTimes->begin(), literalTimes->end()),
                        literalTimes->end());
    sort(timeRanges->begin(), timeRanges->end());
    timeRanges->erase(unique(timeRanges->begin(), timeRanges->end()),
                      timeRanges->end());
}

struct ReportParams
{
    TfPatternMatcher *pathMatcher = nullptr;
    TfPatternMatcher *fieldMatcher = nullptr;
    SortKey sortKey;
    vector<double> literalTimes;
    vector<pair<double, double>> timeRanges;
    double timeTolerance;
    bool showSummary = false;
    bool validate = false;
    bool showValues = true;
    bool fullArrays = false;
};

struct SummaryStats
{
    size_t numSpecs = 0;
    size_t numPrimSpecs = 0;
    size_t numPropertySpecs = 0;
    size_t numFields = 0;
    size_t numSampleTimes = 0;
};

SummaryStats
GetSummaryStats(SdfLayerHandle const &layer)
{
    SummaryStats stats;
    layer->Traverse(
        SdfPath::AbsoluteRootPath(), [&stats, &layer](SdfPath const &path) {
            ++stats.numSpecs;
            stats.numPrimSpecs += path.IsPrimPath();
            stats.numPropertySpecs += path.IsPropertyPath();
            stats.numFields += layer->ListFields(path).size();
        });
    stats.numSampleTimes = layer->ListAllTimeSamples().size();
    return stats;
}

vector<SdfPath>
CollectPaths(SdfLayerHandle const &layer, ReportParams const &p)
{
    vector<SdfPath> result;
    layer->Traverse(SdfPath::AbsoluteRootPath(),
                    [&result, &p](SdfPath const &path) {
                        if (p.pathMatcher->Match(path.GetString()))
                            result.push_back(path);
                    });
    return result;
}

vector<TfToken>
CollectFields(SdfLayerHandle const &layer, SdfPath const &path,
              ReportParams const &p)
{
    vector<TfToken> fields = layer->ListFields(path);
    fields.erase(remove_if(fields.begin(), fields.end(),
                           [&p](TfToken const &f) {
                               return !p.fieldMatcher->Match(f.GetString());
                           }),
                 fields.end());
    return fields;
}

string
GetValueString(VtValue const &value, ReportParams const &p)
{
    return (!p.fullArrays && value.IsArrayValued()) ?
        TfStringPrintf("%s size %zu", value.GetTypeName().c_str(),
                       value.GetArraySize()) :
        TfStringPrintf("%s = %s", value.GetTypeName().c_str(),
                       TfStringify(value).c_str());
}

string
GetTimeSamplesValueString(SdfLayerHandle const &layer,
                          SdfPath const &path, ReportParams const &p)
{
    // Pull all the sample times for the given path, then collect up by p's
    // literalTimes and timeRanges, then if we're pulling values we'll do that
    // for each sample, and format.
    bool takeAllTimes = p.literalTimes.empty() && p.timeRanges.empty();
    auto times = layer->ListTimeSamplesForPath(path);
    vector<double> selectedTimes;
    selectedTimes.reserve(times.size());

    if (takeAllTimes) {
        selectedTimes.assign(times.begin(), times.end());
    }
    else {
        for (auto time: times) {
            // Check literalTimes.
            auto rng = equal_range(
                p.literalTimes.begin(), p.literalTimes.end(), time,
                [&p](double a, double b)  {
                    return IsClose(a, b, p.timeTolerance) ? false : a < b;
                });
            if (rng.first != rng.second)
                selectedTimes.push_back(time);

            // Check ranges.
            for (auto const &range: p.timeRanges) {
                if (range.first <= time && time <= range.second)
                    selectedTimes.push_back(time);
            }
        }
    }

    if (selectedTimes.empty())
        return "<no samples at requested times>";

    vector<string> result;
    VtValue val;
    for (auto time: selectedTimes) {
        TF_VERIFY(layer->QueryTimeSample(path, time, &val));
        result.push_back(
            TfStringPrintf("%s: %s", TfStringify(time).c_str(),
                           GetValueString(val, p).c_str()));
    }
    return TfStringPrintf("[\n        %s ]",
                          TfStringJoin(result, "\n        ").c_str());
}

string
GetFieldValueString(SdfLayerHandle const &layer,
                    SdfPath const &path, TfToken const &field,
                    ReportParams const &p)
{
    string result;
    // Handle timeSamples specially:
    if (field == SdfFieldKeys->TimeSamples) {
        result = GetTimeSamplesValueString(layer, path, p);
    } else {
        VtValue value;
        TF_VERIFY(layer->HasField(path, field, &value));
        result = GetValueString(value, p);
    }
    return result;
}

void
GetReportByPath(SdfLayerHandle const &layer, ReportParams const &p,
                vector<string> &report)
{
    vector<SdfPath> paths = CollectPaths(layer, p);
    sort(paths.begin(), paths.end());
    for (auto const &path: paths) {
        SdfSpecType specType = layer->GetSpecType(path);
        report.push_back(
            TfStringPrintf(
                "<%s> : %s",
                path.GetText(), TfStringify(specType).c_str()));

        vector<TfToken> fields = CollectFields(layer, path, p);
        if (fields.empty())
            continue;
        for (auto const &field: fields) {
            if (p.showValues) {
                report.push_back(
                    TfStringPrintf(
                        "  %s: %s", field.GetText(),
                        GetFieldValueString(layer, path, field, p).c_str())
                    );
            } else {
                report.push_back(TfStringPrintf("  %s", field.GetText()));
            }
        }
    }
}

void
GetReportByField(SdfLayerHandle const &layer, ReportParams const &p,
                 vector<string> &report)
{
    vector<SdfPath> paths = CollectPaths(layer, p);
    unordered_map<string, vector<string>> pathsByFieldString;
    unordered_set<string> allFieldStrings;
    sort(paths.begin(), paths.end());
    for (auto const &path: paths) {
        vector<TfToken> fields = CollectFields(layer, path, p);
        if (fields.empty())
            continue;
        for (auto const &field: fields) {
            string fieldString;
            if (p.showValues) {
                fieldString = TfStringPrintf(
                    "%s: %s", field.GetText(),
                    GetFieldValueString(layer, path, field, p).c_str());
            } else {
                fieldString = TfStringPrintf("%s", field.GetText());
            }
            pathsByFieldString[fieldString].push_back(
                TfStringPrintf("  <%s>", path.GetText()));
            allFieldStrings.insert(fieldString);
        }
    }
    vector<string> fsvec(allFieldStrings.begin(), allFieldStrings.end());
    sort(fsvec.begin(), fsvec.end());

    for (auto const &fs: fsvec) {
        report.push_back(fs);
        auto const &ps = pathsByFieldString[fs];
        report.insert(report.end(), ps.begin(), ps.end());
    }
}

void
Validate(SdfLayerHandle const &layer, ReportParams const &p,
         vector<string> &report)
{
    TfErrorMark m;
    TF_DESCRIBE_SCOPE("Collecting paths in @%s@",
                      layer->GetIdentifier().c_str());
    vector<SdfPath> paths;
    layer->Traverse(SdfPath::AbsoluteRootPath(),
                    [&paths, &p, layer](SdfPath const &path) {
                        TF_DESCRIBE_SCOPE(
                            "Collecting path <%s> in @%s@",
                            path.GetText(), layer->GetIdentifier().c_str());
                        paths.push_back(path);
                    });
    sort(paths.begin(), paths.end());
    for (auto const &path: paths) {
        TF_DESCRIBE_SCOPE("Collecting fields for <%s> in @%s@",
                     path.GetText(), layer->GetIdentifier().c_str());
        vector<TfToken> fields = layer->ListFields(path);
        if (fields.empty())
            continue;
        for (auto const &field: fields) {
            VtValue value;
            if (field == SdfFieldKeys->TimeSamples) {
                // Pull each sample value individually.
                TF_DESCRIBE_SCOPE(
                    "Getting sample times for '%s' on <%s> in @%s@",
                    field.GetText(), path.GetText(),
                    layer->GetIdentifier().c_str());
                auto times = layer->ListTimeSamplesForPath(path);

                for (auto time: times) {
                    TF_DESCRIBE_SCOPE("Getting sample value at time "
                                      "%f for '%s' on <%s> in @%s@",
                                      time, field.GetText(), path.GetText(),
                                      layer->GetIdentifier().c_str());
                    layer->QueryTimeSample(path, time, &value);
                }
            } else {
                // Just pull value.
                TF_DESCRIBE_SCOPE("Getting value for '%s' on <%s> in @%s@",
                                  field.GetText(), path.GetText(),
                                  layer->GetIdentifier().c_str());
                layer->HasField(path, field, &value);
            }
        }
    }
    report.back() += m.IsClean() ? " - OK" : " - ERROR";
}

void Report(SdfLayerHandle layer, ReportParams const &p)
{
    vector<string> report = {
        TfStringPrintf("@%s@", layer->GetIdentifier().c_str()) };
    if (p.showSummary) {
        auto stats = GetSummaryStats(layer);
        report.push_back(
            TfStringPrintf(
                "  %zu specs, %zu prim specs, %zu property specs, %zu fields, "
                "%zu sample times",
                stats.numSpecs, stats.numPrimSpecs, stats.numPropertySpecs,
                stats.numFields, stats.numSampleTimes));
    } else if (p.validate) {
        Validate(layer, p, report);
    } else if (p.sortKey.key == "path") {
        GetReportByPath(layer, p, report);
    } else if (p.sortKey.key == "field") {
        GetReportByField(layer, p, report);
    }

    for (auto const &str: report) {
        Print("%s\n", str.c_str());
    }
}

} // anon

PXR_NAMESPACE_CLOSE_SCOPE

int
main(int argc, char const *argv[])
{
    namespace po = boost::program_options;
    PXR_NAMESPACE_USING_DIRECTIVE

    progName = TfGetBaseName(argv[0]);

    bool showSummary = false, validate = false,
        fullArrays = false, noValues = false;
    SortKey sortKey("path");
    string pathRegex = ".*", fieldRegex = ".*";
    vector<string> timeSpecs, inputFiles;
    vector<double> literalTimes;
    vector<pair<double, double>> timeRanges;
    double timeTolerance = 1.25e-4; // ugh -- chosen to print well in help.

    po::options_description argOpts("Options");
    argOpts.add_options()
        ("help,h", "Show help message.")
        ("summary,s", po::bool_switch(&showSummary),
         "Report a high-level summary.")
        ("validate", po::bool_switch(&validate),
         "Check validity by trying to read all data values.")
        ("path,p", po::value<string>(&pathRegex)->value_name("regex"),
         "Report only paths matching this regex.")
        ("field,f", po::value<string>(&fieldRegex)->value_name("regex"),
         "Report only fields matching this regex.")
        ("time,t", po::value<vector<string>>(&timeSpecs)->
         multitoken()->value_name("n or ff..lf"),
         "Report only these times or time ranges for 'timeSamples' fields.")
        ("timeTolerance", po::value<double>(&timeTolerance)->
         default_value(timeTolerance)->value_name("tol"),
         "Report times that are close to those requested within this "
         "relative tolerance.")
        ("sortBy", po::value<SortKey>(&sortKey)->default_value(sortKey)->
         value_name("path|field"),
         "Group output by either path or field.")
        ("noValues", po::bool_switch(&noValues),
         "Do not report field values.")
        ("fullArrays", po::bool_switch(&fullArrays),
         "Report full array contents rather than number of elements.")
        ;

    po::options_description inputFile("Input");
    inputFile.add_options()
        ("input-file", po::value<vector<string>>(&inputFiles), "input files");

    po::options_description allOpts;
    allOpts.add(argOpts).add(inputFile);

    po::variables_map vm;
    try {
        po::positional_options_description p;
        p.add("input-file", -1);
        po::store(po::command_line_parser(argc, argv).
                  options(allOpts).positional(p).run(), vm);
        po::notify(vm);
        ParseTimes(timeSpecs, &literalTimes, &timeRanges);
    } catch (std::exception const &e) {
        ErrExit("%s", e.what());
    }

    if (vm.count("help") || inputFiles.empty()) {
        fprintf(stderr, "Usage: %s [options] <input file>\n", progName.c_str());
        fprintf(stderr, "%s\n", TfStringify(argOpts).c_str());
        exit(1);
    }

    TfPatternMatcher pathMatcher(pathRegex);
    if (!pathMatcher.IsValid()) {
        ErrExit("path regex '%s' : %s", pathRegex.c_str(),
                pathMatcher.GetInvalidReason().c_str());
    }

    TfPatternMatcher fieldMatcher(fieldRegex);
    if (!fieldMatcher.IsValid()) {
        ErrExit("field regex '%s' : %s", fieldRegex.c_str(),
                fieldMatcher.GetInvalidReason().c_str());
    }

    ReportParams params;
    params.showSummary = showSummary;
    params.validate = validate;
    params.pathMatcher = &pathMatcher;
    params.fieldMatcher = &fieldMatcher;
    params.sortKey = sortKey;
    params.literalTimes = literalTimes;
    params.timeRanges = timeRanges;
    params.showValues = !noValues;
    params.fullArrays = fullArrays;
    params.timeTolerance = timeTolerance;

    for (auto const &file: inputFiles) {
        TF_DESCRIBE_SCOPE("Opening layer @%s@", file.c_str());
        auto layer = SdfLayer::FindOrOpen(file);
        if (!layer) {
            Err("failed to open layer <%s>", file.c_str());
            continue;
        }
        Report(layer, params);
    }

    return 0;
}

max_stars_repo_name: WD-stefaang/USD

max_issues_repo_name: WD-stefaang/USD

max_forks_repo_name: WD-stefaang/USD


text:
//
// Created by Tyler on 10/23/21.
//

#include <ndn-svs/svspubsub.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
#include <ndn-cxx/util/scheduler.hpp>
#include <ndn-cxx/util/io.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>
#include <iostream>
#include <random>

namespace po = boost::program_options;
using namespace ndn;

std::random_device rd;  //Will be used to obtain a seed for the random number engine
std::mt19937 random_gen(rd()); //Standard mersenne_twister_engine seeded with rd()

void periodicAddRecord(KeyChain& keychain, shared_ptr<svs::SVSPubSub> pubSub, const Name& peerPrefix, Scheduler &scheduler) {
    std::uniform_int_distribution<int> distribution(0, INT_MAX);
    Data data(Name(peerPrefix).append(std::to_string(distribution(random_gen))));
    data.setContent(makeStringBlock(tlv::Content, std::to_string(distribution(random_gen))));
    keychain.sign(data, signingByIdentity(peerPrefix));

    std::cout << "publishing: " << data.getFullName() << std::endl;
    pubSub->publishData(data);

    // schedule for the next record generation
    scheduler.schedule(time::seconds(5), [&keychain, pubSub, peerPrefix, &scheduler] { periodicAddRecord(keychain, pubSub, peerPrefix, scheduler); });
}

int main(int argc, char **argv) {
    po::options_description description("Usage for Mnemosyne Test Client");

    description.add_options()
            ("help,h", "Display this help message")
            ("interface-ps-prefix,i", po::value<std::string>()->default_value("/ndn/broadcast/mnemosyne"), "The prefix for Interface Pub/Sub")
            ("client-prefix,c", po::value<std::string>(), "The prefix for the client");

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

    if(vm.count("help")){
        std::cout << description;
        return 0;
    }

    if (vm.count("client-prefix") == 0) {
        std::cout << "missing parameter: Client Prefix\n";
        return 2;
    }

    boost::asio::io_service ioService;
    Face face(ioService);
    security::KeyChain keychain;

    std::shared_ptr<svs::SVSPubSub> interfacePS = std::make_shared<svs::SVSPubSub>(vm["interface-ps-prefix"].as<std::string>(), vm["client-prefix"].as<std::string>(), face, nullptr);

    Scheduler scheduler(ioService);
    periodicAddRecord(keychain, interfacePS, vm["client-prefix"].as<std::string>(), scheduler);

    face.processEvents();
    return 0;
}

max_stars_repo_name: UCLA-IRL/Mnemosyne

max_issues_repo_name: UCLA-IRL/Mnemosyne

max_forks_repo_name: UCLA-IRL/Mnemosyne