Skip to content

Commit

Permalink
Merge pull request #1127 from LLNL/feature/kweiss/shaping-3D-rz
Browse files Browse the repository at this point in the history
Allows registering callback functions for projecting input points before querying sample-based shaper
  • Loading branch information
kennyweiss committed Jul 18, 2023
2 parents e30d836 + 1ed6add commit c9d402d
Show file tree
Hide file tree
Showing 30 changed files with 1,791 additions and 265 deletions.
6 changes: 6 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ The Axom project release numbers follow [Semantic Versioning](http://semver.org/
- Adds an `ArrayView::subspan()` overload for multi-dimensional subspans
- Adds an `axom::utilities::insertionSort()` method.
- Quest: Adds Pro/E tetrahedral meshes as input to the `IntersectionShaper`
- Quest: For sample-based shaping, users can register callback functions to modify the input points
before querying the spatial index. This allows, e.g. querying 3D points against 2D surfaces
of revolution provided as c2c contour files.
- Adds an ``axom::utilities::locale`` utility function to guard against platforms that do not have the requested
locales via the `std::locale` function. If the system does not have the requested locale (e.g. `en_US.UTF8`),
it returns the user's default locale.

### Changed
- Fixed bug in `mint::mesh::UnstructuredMesh` constructors, affecting capacity.
Expand Down
10 changes: 7 additions & 3 deletions src/axom/core/ArrayBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,14 +492,18 @@ class ArrayBase
[&](int dim_a, int dim_b) -> bool {
return stride[dim_a] < stride[dim_b];
});
// Work from the smallest-strided dimension to the largest-strided.
// Work from the smallest-strided dimension to the largest-strided.
#ifndef NDEBUG
for(int dim = 0; dim < DIM - 1; dim++)
{
int minor_dim = sorted_dims[dim];
int major_dim = sorted_dims[dim + 1];
const int& minor_dim = sorted_dims[dim];
const int& major_dim = sorted_dims[dim + 1];
assert(stride[major_dim] >= stride[minor_dim] * shape[minor_dim]);
assert(stride[major_dim] % stride[minor_dim] == 0);
}
#else
AXOM_UNUSED_VAR(shape);
#endif
}

/// @}
Expand Down
1 change: 1 addition & 0 deletions src/axom/core/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ set(core_serial_tests

utils_endianness.hpp
utils_fileUtilities.hpp
utils_locale.hpp
utils_nvtx_settings.hpp
utils_stringUtilities.hpp
utils_system.hpp
Expand Down
1 change: 1 addition & 0 deletions src/axom/core/tests/core_serial_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#include "utils_endianness.hpp"
#include "utils_fileUtilities.hpp"
#include "utils_locale.hpp"
#include "utils_nvtx_settings.hpp"
#include "utils_stringUtilities.hpp"
#include "utils_system.hpp"
Expand Down
268 changes: 268 additions & 0 deletions src/axom/core/tests/utils_locale.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
// Copyright (c) 2017-2023, Lawrence Livermore National Security, LLC and
// other Axom Project Developers. See the top-level LICENSE file for details.
//
// SPDX-License-Identifier: (BSD-3-Clause)

//-----------------------------------------------------------------------------
//
// file: utils_locale.hpp
// Checks locales and prints out related info
//
//-----------------------------------------------------------------------------

#include "axom/core/utilities/StringUtilities.hpp"
#include "axom/core/utilities/System.hpp"

#include "axom/fmt.hpp"

#include <locale>
#include <string>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <array>
#include <vector>
#include <set>
#include <algorithm>

#include "gtest/gtest.h"

#ifdef _WIN32
#include <Windows.h>
#endif

namespace
{
#ifdef __linux__
/**
* \brief Utility function to capture output of system call
* \note Adapted from https://stackoverflow.com/a/478960
*/
std::string execute_command(const std::string& cmd)
{
std::array<char, 128> buffer;
std::string result;

std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
if(!pipe)
{
throw std::runtime_error(
axom::fmt::format("popen() failed for command '{}'", cmd));
}

while(fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
result += buffer.data();
}

return result;
}
#endif // __linux__

#ifdef _WIN32
/// callback function for EnumSystemLocaleEx call in enumerate_locales_windows test
/// note: We're expecting the LPARAM to be a pointer to a vector of wide strings
BOOL CALLBACK MyFuncLocaleEx(LPWSTR pStr, DWORD dwFlags, LPARAM strvec_ptr)
{
using StrVec = std::vector<std::wstring>;
reinterpret_cast<StrVec*>(strvec_ptr)->push_back(pStr);
return TRUE;
}
#endif

} // end anonymous namespace

//-----------------------------------------------------------------------------
TEST(utils_locale, default_locale)
{
// This test is informative -- it will print the default and user locales
std::locale loc(std::locale(), new std::ctype<char>);
std::cout << "The default locale is " << std::locale().name() << '\n'
<< "The user's locale is " << std::locale("").name() << '\n'
<< "Nameless locale is " << loc.name() << '\n';
}

//-----------------------------------------------------------------------------
TEST(utils_locale, check_en_US_locale)
{
// This test is informative; not having en_US should not fail the test
try
{
std::locale loc("en_US.UTF-8");
std::cout << "Name after setting locale to 'en_US.UTF-8': " << loc.name()
<< std::endl;
}
catch(std::runtime_error&)
{
std::cout << "Could not set locale to 'en_US.UTF-8'" << std::endl;
}
}

TEST(utils_locale, try_catch)
{
std::locale loc; // initialized to locale::classic()
try
{
loc = std::locale("en_US.UTF-8");
}
catch(std::runtime_error&)
{
loc = std::locale(loc, "", std::locale::ctype);
}

std::cout << "The selected locale after attempting to use 'en_US.UTF-8' "
"with try/catch is: "
<< loc.name() << std::endl;
}

TEST(utils_locale, axom_locale_default)
{
try
{
const auto loc = axom::utilities::locale();
std::cout << axom::fmt::format("Axom's default locale is: '{}'\n",
loc.name());
}
catch(std::runtime_error&)
{
FAIL() << "Could not initialize a valid default locale\n";
}
}

TEST(utils_locale, axom_locale_variations)
{
const std::int32_t ii = 10000000;
const std::int64_t ll = 9999999999999ll;
const double dd = 12345.6789;

// check several different variations, including some invalid ones
for(auto& loc_str : {"<DEFAULT>",
"",
"C",
"C.utf8",
"en_US",
"en_US.utf8",
"en_US.UTF8",
"en_US.UTF-8",
"NON-EXISTENT"})
{
try
{
const auto loc = (loc_str == std::string("<DEFAULT>"))
? axom::utilities::locale()
: axom::utilities::locale(loc_str);

std::cout << axom::fmt::format("Locale for '{}' is '{}'\n",
loc_str,
loc.name());

std::cout << axom::fmt::format(
loc,
"Formatting an int32 using the locale {:L}\n",
ii);
std::cout << axom::fmt::format(
loc,
"Formatting an int64 using the locale {:L}\n",
ll);
std::cout << axom::fmt::format(
loc,
"Formatting a double using the locale {:L}\n",
dd);
}
catch(std::runtime_error&)
{
FAIL() << axom::fmt::format(
"Could not initialize a valid locale for '{}'\n",
loc_str);
}
}
}

#ifdef __linux__
TEST(utils_locale, enumerate_locales_linux)
{
std::vector<std::string> locale_list;
std::vector<std::string> available_locales;

// get list of locales by running "locale -a" system call
try
{
std::string output = ::execute_command("locale -a");
locale_list = axom::utilities::string::split(output, '\n');
}
catch(const std::runtime_error& e)
{
std::cerr << e.what() << '\n';
}

// remove non-ascii strings since they're causing problems on blueos
auto is_non_ascii = [](char c) { return static_cast<unsigned char>(c) > 127; };
locale_list.erase(
std::remove_if(locale_list.begin(),
locale_list.end(),
[=](const std::string& s) {
return std::any_of(s.begin(), s.end(), is_non_ascii);
}),
locale_list.end());

// sort and unique-ify the list
std::sort(locale_list.begin(), locale_list.end());
locale_list.erase(std::unique(locale_list.begin(), locale_list.end()),
locale_list.end());

// check if each item can successfully be used to create a locale
for(const auto& loc_str : locale_list)
{
try
{
auto loc = std::locale(loc_str);
available_locales.push_back(loc.name());
}
catch(std::runtime_error&)
{
// could not instantiate this locale
}
}

std::cout << axom::fmt::format("{} available locales on this system: '{}'\n",
available_locales.size(),
axom::fmt::join(available_locales, "', '"));
}
#endif // __linux__

#ifdef _WIN32
TEST(utils_locale, enumerate_locales_windows)
{
std::vector<std::wstring> locale_list;
std::vector<std::string> available_locales;

// get vector of locales on this system
// note: we have to cast the locale_list pointer to an LPARAM to satisfy the Windows API
LPARAM lparam = reinterpret_cast<LPARAM>(&locale_list);
EnumSystemLocalesEx(MyFuncLocaleEx, LOCALE_ALL, lparam, nullptr);

// sort and unique-ify the list
std::sort(locale_list.begin(), locale_list.end());
locale_list.erase(std::unique(locale_list.begin(), locale_list.end()),
locale_list.end());

// check if each item can successfully be used to create a locale
for(const auto& loc_str : locale_list)
{
try
{
auto loc = std::locale(std::string(loc_str.begin(), loc_str.end()));
available_locales.push_back(loc.name());
}
catch(std::runtime_error&)
{
// could not instantiate this locale
}
}

std::cout << axom::fmt::format("{} available locales on this system: '{}'\n",
available_locales.size(),
axom::fmt::join(available_locales, "', '"));
}
#endif // _WIN32
18 changes: 17 additions & 1 deletion src/axom/core/utilities/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ std::string getUserName()
else
{
// fallback on getpwuid if getlogin_r fails
struct passwd *pwd = getpwuid(getuid());
struct passwd* pwd = getpwuid(getuid());
if(pwd)
{
userName = std::string(pwd->pw_name);
Expand All @@ -87,5 +87,21 @@ std::string getUserName()
return userName;
}

std::locale locale(const std::string& name)
{
std::locale loc;

try
{
loc = std::locale(name);
}
catch(std::runtime_error&)
{
loc = std::locale(loc, "", std::locale::ctype);
}

return loc;
}

} // end namespace utilities
} // end namespace axom
8 changes: 8 additions & 0 deletions src/axom/core/utilities/System.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define CORE_SYSTEM_UTILITIES_H_

#include <string>
#include <locale>

namespace axom
{
Expand All @@ -26,6 +27,13 @@ std::string getHostName();
*/
std::string getUserName();

/**
* @brief Returns a valid locale for the current system
*
* @param name The name of the desired locale
*/
std::locale locale(const std::string& name = "en_US.UTF-8");

} // end namespace utilities
} // end namespace axom

Expand Down
3 changes: 0 additions & 3 deletions src/axom/inlet/Verifiable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,6 @@ class AggregateVerifiable : public Verifiable<BaseType>
: m_verifiables(std::move(verifiables))
{ }

// Should not be reassignable
AggregateVerifiable& operator=(const AggregateVerifiable&) = delete;

AggregateVerifiable& required(bool isRequired = true) override
{
for(auto& verifiable : m_verifiables)
Expand Down
2 changes: 2 additions & 0 deletions src/axom/multimat/multimat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,8 @@ class MultiMat
FieldBacking(axom::ArrayView<const T> input_array, bool owned, int allocatorID)
{
SLIC_ASSERT(owned == true);
AXOM_UNUSED_VAR(owned);

m_isOwned = true;
getArray<T>() = axom::Array<T>(input_array, allocatorID);
}
Expand Down

0 comments on commit c9d402d

Please sign in to comment.