Skip to content

Commit

Permalink
env handling
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilipDeegan committed Jun 21, 2024
1 parent fc41581 commit 1bce4ce
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 38 deletions.
1 change: 1 addition & 0 deletions res/cmake/test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ if (test AND ${PHARE_EXEC_LEVEL_MIN} GREATER 0) # 0 = no tests
add_subdirectory(tests/core/data/maxwellian_particle_initializer)
add_subdirectory(tests/core/data/particle_initializer)
add_subdirectory(tests/core/utilities/box)
add_subdirectory(tests/core/utilities/env)
add_subdirectory(tests/core/utilities/range)
add_subdirectory(tests/core/utilities/index)
add_subdirectory(tests/core/utilities/indexer)
Expand Down
98 changes: 98 additions & 0 deletions src/core/env.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#ifndef PHARE_CORE_ENV_HPP
#define PHARE_CORE_ENV_HPP

// Single source for handling env vars

#include <array>
#include <cstdint>
#include <optional>
#include <string_view>
#include "core/utilities/types.hpp"
#include "core/utilities/mpi_utils.hpp"

namespace PHARE::env
{

struct Var
{
using value_type = std::string;

std::string_view const id;
std::string_view const desc;
std::vector<std::pair<std::string_view, std::string_view>> const options;

std::optional<value_type> const _default = std::nullopt;
std::function<std::string(Var const&)> const _result
= [](Var const&) { return std::string{""}; }; // noop
std::optional<value_type> const v = get();
std::string const r = _result(*this);

std::optional<value_type> get() const
{
std::string _id{id};
if (_default)
return core::get_env(_id, *_default);
return core::get_env(_id);
}
auto& operator()() const { return v; }
bool exists() const { return v != std::nullopt; }
operator bool() const { return exists(); }
auto result() const { return r; }
};

} // namespace PHARE::env

namespace PHARE
{

class Env
{
public:
template<typename T>
using map_t = std::unordered_map<std::string, T const* const>;

static Env& INSTANCE()
{
if (!self)
self = std::make_unique<Env>();
return *self;
}
static auto& reinit() { return *(self = std::make_unique<Env>()); }

env::Var const PHARE_LOG{
"PHARE_LOG",
"Write logs to $CWD/.log",
{{{"RANK_FILES", "Write logs $CWD/.log, a file per rank"},
{"DATETIME_FILES", "Write logs $CWD/.log, filename per rank and datetime"},
{"NONE", "print normally to std::cout"}}},
std::nullopt,
[](auto const& self) {
if (auto const& opt = self())
{
auto const& val = *opt;
if (val == "RANK_FILES")
return ".log/" + std::to_string(core::mpi::rank()) + ".out";
if (val == "DATETIME_FILES")
{
auto date_time = core::mpi::date_time();
auto rank = std::to_string(core::mpi::rank());
auto size = std::to_string(core::mpi::size());
return ".log/" + date_time + "_" + rank + "_of_" + size + ".out";
}
if (val != "NONE")
throw std::runtime_error(
"PHARE_LOG invalid type, valid keys are RANK_FILES/DATETIME_FILES/NONE");
}
return std::string{""};
} //
};

map_t<env::Var> const vars = {{{"PHARE_LOG", &PHARE_LOG}}};

private:
static inline std::unique_ptr<Env> self = nullptr;
};

} // namespace PHARE

#endif /* PHARE_CORE_ERRORS_H */
1 change: 1 addition & 0 deletions src/core/utilities/mpi_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ std::size_t max(std::size_t const local, int mpi_size)




bool any(bool b)
{
int global_sum, local_sum = static_cast<int>(b);
Expand Down
8 changes: 8 additions & 0 deletions src/core/utilities/mpi_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ inline bool is_init()
return flag > 0;
}


struct Lifecycle
{
Lifecycle(int argc, char** argv) { MPI_Init(&argc, &argv); }
~Lifecycle() { MPI_Finalize(); }
};


template<typename Data>
NO_DISCARD auto mpi_type_for()
{
Expand Down
27 changes: 27 additions & 0 deletions src/core/utilities/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,15 @@ namespace core
T var;
};

template<typename T>
NO_DISCARD T from_string(std::string const& s)
{
T t;
std::stringstream ss(s);
ss >> t;
return t;
}

template<typename T>
NO_DISCARD std::string to_string_with_precision(T const& a_value, std::size_t const len)
{
Expand Down Expand Up @@ -246,6 +255,24 @@ namespace core
}


template<typename T>
NO_DISCARD inline std::optional<T> get_env_as(std::string const& key)
{
if (auto e = get_env(key))
return from_string<T>(*e);
return std::nullopt;
}


template<typename T>
NO_DISCARD inline T get_env_as(std::string const& key, T const& t)
{
if (auto e = get_env(key))
return from_string<T>(*e);
return t;
}



} // namespace core
} // namespace PHARE
Expand Down
15 changes: 4 additions & 11 deletions src/hdf5/detail/h5/h5_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,7 @@ class HighFiveFile

~HighFiveFile() {}

NO_DISCARD HiFile& file()
{
return h5file_;
}
NO_DISCARD HiFile& file() { return h5file_; }


template<typename T, std::size_t dim = 1>
Expand Down Expand Up @@ -146,15 +143,11 @@ class HighFiveFile
void write_attribute(std::string const& keyPath, std::string const& key, Data const& data)
{
// assumes all keyPaths and values are identical, and no null patches
// clang-format off
PHARE_DEBUG_DO(
PHARE_DEBUG_DO( //
auto const paths = core::mpi::collect(keyPath, core::mpi::size());
for (auto const& path : paths)
PHARE_LOG_LINE_STR(std::to_string(core::mpi::size()) << " " << path)
if (!core::all(paths, [&](auto const& path) { return path == paths[0]; }))
throw std::runtime_error("Function does not support different paths per mpi core");
if (!core::all(paths, [&](auto const& path) { return path == paths[0]; })) throw std::
runtime_error("Function does not support different paths per mpi core"); //
)
// clang-format on

constexpr bool data_is_vector = core::is_std_vector_v<Data>;

Expand Down
12 changes: 12 additions & 0 deletions src/python3/cpp_etc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "python3/pybind_def.hpp"
#include "simulator/simulator.hpp"

#include "core/env.hpp"
#include "core/def/phare_config.hpp"


Expand Down Expand Up @@ -55,5 +56,16 @@ PYBIND11_MODULE(cpp_etc, m)
});

m.def("phare_build_config", []() { return PHARE::build_config(); });

m.def("phare_env_exists",
[](std::string const& s) { return Env::INSTANCE().vars.count(s) > 0; });
m.def("phare_env_val", [](std::string const& s) {
assert(Env::INSTANCE().vars.count(s) > 0);
return (*Env::INSTANCE().vars.at(s))();
});
m.def("phare_env_result", [](std::string const& s) {
assert(Env::INSTANCE().vars.count(s) > 0);
return Env::INSTANCE().vars.at(s)->result();
});
}
} // namespace PHARE::pydata
30 changes: 3 additions & 27 deletions src/simulator/simulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "phare_types.hpp"

#include "core/def.hpp"
#include "core/env.hpp"
#include "core/logger.hpp"
#include "core/utilities/types.hpp"
#include "core/utilities/mpi_utils.hpp"
Expand Down Expand Up @@ -110,32 +111,7 @@ class Simulator : public ISimulator
private:
auto find_model(std::string name);

auto static log_file_name()
{
// ".log" directory is not created here, but in python if PHARE_LOG != "NONE"
if (auto log = core::get_env("PHARE_LOG"))
{
if (log == "RANK_FILES")
return ".log/" + std::to_string(core::mpi::rank()) + ".out";


if (log == "DATETIME_FILES")
{
auto date_time = core::mpi::date_time();
auto rank = std::to_string(core::mpi::rank());
auto size = std::to_string(core::mpi::size());
return ".log/" + date_time + "_" + rank + "_of_" + size + ".out";
}

if (log != "NONE")
throw std::runtime_error(
"PHARE_LOG invalid type, valid keys are RANK_FILES/DATETIME_FILES/NONE");
}

return std::string{""}; // unused
}

std::ofstream log_out{log_file_name()};
std::ofstream log_out{Env::INSTANCE().PHARE_LOG.result()};
std::streambuf* coutbuf = nullptr;
std::shared_ptr<PHARE::amr::Hierarchy> hierarchy_;
std::unique_ptr<Integrator> integrator_;
Expand Down Expand Up @@ -186,7 +162,7 @@ namespace
inline auto logging(std::ofstream& log_out)
{
std::streambuf* buf = nullptr;
if (auto log = core::get_env("PHARE_LOG"); log != "NONE")
if (auto log = Env::INSTANCE().PHARE_LOG(); log and log != "NONE")
{
buf = std::cout.rdbuf();
std::cout.rdbuf(log_out.rdbuf());
Expand Down
21 changes: 21 additions & 0 deletions tests/core/utilities/env/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
cmake_minimum_required (VERSION 3.20.1)

project(test-phare-env)

set(SOURCES test_env.cpp)

add_executable(${PROJECT_NAME} ${SOURCES})

target_include_directories(${PROJECT_NAME} PRIVATE
${GTEST_INCLUDE_DIRS}
)

target_link_directories(${PROJECT_NAME} PUBLIC ${MPI_LIBRARY_PATH})

target_link_libraries(${PROJECT_NAME} PRIVATE
phare_core
MPI::MPI_C
${GTEST_LIBS}
)

add_phare_test(${PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR})
46 changes: 46 additions & 0 deletions tests/core/utilities/env/test_env.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@


#include "core/env.hpp"
#include "gtest/gtest.h"
#include <cstdlib>

namespace PHARE
{

TEST(Env, logging_works)
{
setenv("PHARE_LOG", "NONE", true);
auto& env = Env::reinit(); // init

EXPECT_EQ(env.vars.size(), 1);

for (auto const& [key, var] : env.vars)
{
EXPECT_EQ(key, std::string{"PHARE_LOG"});
EXPECT_EQ(key, std::string{var->id});
}
}

TEST(Env, logging_works_rank_files)
{
setenv("PHARE_LOG", "RANK_FILES", true);
auto& env = Env::reinit(); // init

EXPECT_EQ(env.vars.size(), 1);

for (auto const& [key, var] : env.vars)
{
EXPECT_EQ(key, std::string{"PHARE_LOG"});
EXPECT_EQ(key, std::string{var->id});
EXPECT_EQ(var->result(), ".log/" + std::to_string(core::mpi::rank()) + ".out");
}
}

} // namespace PHARE

int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
PHARE::core::mpi::Lifecycle mpi_init(argc, argv);
return RUN_ALL_TESTS();
}

0 comments on commit 1bce4ce

Please sign in to comment.